vendor: 4,090 bytes, lines 1-103
1/****************************************************************************** 2Copyright (c) Microsoft Corporation. 3 4Permission to use, copy, modify, and/or distribute this software for any 5purpose with or without fee is hereby granted. 6 7THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 9AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 11LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 12OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 13PERFORMANCE OF THIS SOFTWARE. 14***************************************************************************** */ 15/* global Reflect, Promise, SuppressedError, Symbol, Iterator */ 16 17var extendStatics = function(d, b) { 18 extendStatics = Object.setPrototypeOf || 19 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 20 function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; 21 return extendStatics(d, b); 22}; 23 24function __extends(d, b) { 25 if (typeof b !== "function" && b !== null) 26 throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); 27 extendStatics(d, b); 28 function __() { this.constructor = d; } 29 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 30} 31 32var __assign = function() { 33 __assign = Object.assign || function __assign(t) { 34 for (var s, i = 1, n = arguments.length; i < n; i++) { 35 s = arguments[i]; 36 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; 37 } 38 return t; 39 }; 40 return __assign.apply(this, arguments); 41}; 42 43function __decorate(decorators, target, key, desc) { 44 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 45 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 46 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 47 return c > 3 && r && Object.defineProperty(target, key, r), r; 48} 49 50function __param(paramIndex, decorator) { 51 return function (target, key) { decorator(target, key, paramIndex); } 52} 53 54function __metadata(metadataKey, metadataValue) { 55 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); 56} 57 58function __read(o, n) { 59 var m = typeof Symbol === "function" && o[Symbol.iterator]; 60 if (!m) return o; 61 var i = m.call(o), r, ar = [], e; 62 try { 63 while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); 64 } 65 catch (error) { e = { error: error }; } 66 finally { 67 try { 68 if (r && !r.done && (m = i["return"])) m.call(i); 69 } 70 finally { if (e) throw e.error; } 71 } 72 return ar; 73} 74 75function __spreadArray(to, from, pack) { 76 if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { 77 if (ar || !(i in from)) { 78 if (!ar) ar = Array.prototype.slice.call(from, 0, i); 79 ar[i] = from[i]; 80 } 81 } 82 return to.concat(ar || Array.prototype.slice.call(from)); 83} 84 85typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { 86 var e = new Error(message); 87 return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; 88}; 89 90// Important: this file is generated from the 'build' script and should not be 91// edited directly 92var version = '4.1.5'; 93 94var hasOwnProperty = Object.prototype.hasOwnProperty; 95/** 96 * Simpler helper method to check for a boolean type simply for the benefit of 97 * gaining better compression when minified by not needing to have multiple 98 * `typeof` comparisons in the codebase. 99 */ 100function isBoolean(value) { 101 return typeof value === 'boolean'; 102} 103/**
104 * Truncates the `str` at `len - ellipsisChars.length`, and adds the `ellipsisChars` to the 105 * end of the string (by default, two periods: '..'). If the `str` length does not exceed 106 * `len`, the string will be returned unchanged. 107 * 108 * @param {String} str The string to truncate and add an ellipsis to. 109 * @param {Number} truncateLen The length to truncate the string at. 110 * @param {String} [ellipsisChars=...] The ellipsis character(s) to add to the end of `str` 111 * when truncated. Defaults to '...' 112 */ 113function ellipsis(str, truncateLen, ellipsisChars) { 114 var ellipsisLength; 115 if (str.length > truncateLen) { 116 if (ellipsisChars == null) { 117 ellipsisChars = '…'; 118 ellipsisLength = 3; 119 } 120 else { 121 ellipsisLength = ellipsisChars.length; 122 } 123 str = str.substring(0, truncateLen - ellipsisLength) + ellipsisChars; 124 } 125 return str; 126} 127/** 128 * Removes array elements based on a filtering function. Mutates the input 129 * array. 130 * 131 * Using this instead of the ES5 Array.prototype.filter() function to prevent 132 * creating many new arrays in memory for filtering. 133 * 134 * @param arr The array to remove elements from. This array is mutated. 135 * @param fn The predicate function which should return `true` to remove an 136 * element. 137 */ 138function removeWithPredicate(arr, fn) { 139 for (var i = arr.length - 1; i >= 0; i--) { 140 if (fn(arr[i]) === true) { 141 arr.splice(i, 1); 142 } 143 } 144} 145/** 146 * Function that should never be called but is used to check that every 147 * enum value is handled using TypeScript's 'never' type. 148 */ 149/* istanbul ignore next */ 150function assertNever(theValue) { 151 throw new Error("Unhandled case for value: '".concat(theValue, "'")); 152} 153 154// Regular expression to match whitespace
vendor: 10,889 bytes, lines 155-449
155var whitespaceRe = /\s+/; 156/** 157 * @class Autolinker.HtmlTag 158 * @extends Object 159 * 160 * Represents an HTML tag, which can be used to easily build/modify HTML tags programmatically. 161 * 162 * Autolinker uses this abstraction to create HTML tags, and then write them out as strings. You may also use 163 * this class in your code, especially within a {@link Autolinker#replaceFn replaceFn}. 164 * 165 * ## Examples 166 * 167 * Example instantiation: 168 * 169 * var tag = new Autolinker.HtmlTag( { 170 * tagName : 'a', 171 * attrs : { 'href': 'http://google.com', 'class': 'external-link' }, 172 * innerHtml : 'Google' 173 * } ); 174 * 175 * tag.toAnchorString(); // <a href="http://google.com" class="external-link">Google</a> 176 * 177 * // Individual accessor methods 178 * tag.getTagName(); // 'a' 179 * tag.getAttr( 'href' ); // 'http://google.com' 180 * tag.hasClass( 'external-link' ); // true 181 * 182 * 183 * Using mutator methods (which may be used in combination with instantiation config properties): 184 * 185 * var tag = new Autolinker.HtmlTag(); 186 * tag.setTagName( 'a' ); 187 * tag.setAttr( 'href', 'http://google.com' ); 188 * tag.addClass( 'external-link' ); 189 * tag.setInnerHtml( 'Google' ); 190 * 191 * tag.getTagName(); // 'a' 192 * tag.getAttr( 'href' ); // 'http://google.com' 193 * tag.hasClass( 'external-link' ); // true 194 * 195 * tag.toAnchorString(); // <a href="http://google.com" class="external-link">Google</a> 196 * 197 * 198 * ## Example use within a {@link Autolinker#replaceFn replaceFn} 199 * 200 * var html = Autolinker.link( "Test google.com", { 201 * replaceFn : function( match ) { 202 * var tag = match.buildTag(); // returns an {@link Autolinker.HtmlTag} instance, configured with the Match's href and anchor text 203 * tag.setAttr( 'rel', 'nofollow' ); 204 * 205 * return tag; 206 * } 207 * } ); 208 * 209 * // generated html: 210 * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a> 211 * 212 * 213 * ## Example use with a new tag for the replacement 214 * 215 * var html = Autolinker.link( "Test google.com", { 216 * replaceFn : function( match ) { 217 * var tag = new Autolinker.HtmlTag( { 218 * tagName : 'button', 219 * attrs : { 'title': 'Load URL: ' + match.getAnchorHref() }, 220 * innerHtml : 'Load URL: ' + match.getAnchorText() 221 * } ); 222 * 223 * return tag; 224 * } 225 * } ); 226 * 227 * // generated html: 228 * // Test <button title="Load URL: http://google.com">Load URL: google.com</button> 229 */ 230var HtmlTag = /** @class */ (function () { 231 /** 232 * @method constructor 233 * @param {Object} [cfg] The configuration properties for this class, in an Object (map) 234 */ 235 function HtmlTag(cfg) { 236 if (cfg === void 0) { cfg = {}; } 237 /** 238 * @cfg {String} tagName 239 * 240 * The tag name. Ex: 'a', 'button', etc. 241 * 242 * Not required at instantiation time, but should be set using {@link #setTagName} before {@link #toAnchorString} 243 * is executed. 244 */ 245 this.tagName = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 246 /** 247 * @cfg {Object.<String, String>} attrs 248 * 249 * An key/value Object (map) of attributes to create the tag with. The keys are the attribute names, and the 250 * values are the attribute values. 251 */ 252 this.attrs = {}; // default value just to get the above doc comment in the ES5 output and documentation generator 253 /** 254 * @cfg {String} innerHTML 255 * 256 * The inner HTML for the tag. 257 */ 258 this.innerHTML = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 259 this.tagName = cfg.tagName || ''; 260 this.attrs = cfg.attrs || {}; 261 this.innerHTML = cfg.innerHtml || cfg.innerHTML || ''; // accept either the camelCased form or the fully capitalized acronym as in the DOM 262 } 263 /** 264 * Sets the tag name that will be used to generate the tag with. 265 * 266 * @param {String} tagName 267 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. 268 */ 269 HtmlTag.prototype.setTagName = function (tagName) { 270 this.tagName = tagName; 271 return this; 272 }; 273 /** 274 * Retrieves the tag name. 275 * 276 * @return {String} 277 */ 278 HtmlTag.prototype.getTagName = function () { 279 return this.tagName; 280 }; 281 /** 282 * Sets an attribute on the HtmlTag. 283 * 284 * @param {String} attrName The attribute name to set. 285 * @param {String} attrValue The attribute value to set. 286 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. 287 */ 288 HtmlTag.prototype.setAttr = function (attrName, attrValue) { 289 var tagAttrs = this.getAttrs(); 290 tagAttrs[attrName] = attrValue; 291 return this; 292 }; 293 /** 294 * Retrieves an attribute from the HtmlTag. If the attribute does not exist, returns `undefined`. 295 * 296 * @param {String} attrName The attribute name to retrieve. 297 * @return {String} The attribute's value, or `undefined` if it does not exist on the HtmlTag. 298 */ 299 HtmlTag.prototype.getAttr = function (attrName) { 300 return this.getAttrs()[attrName]; 301 }; 302 /** 303 * Sets one or more attributes on the HtmlTag. 304 * 305 * @param {Object.<String, String>} attrs A key/value Object (map) of the attributes to set. 306 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. 307 */ 308 HtmlTag.prototype.setAttrs = function (attrs) { 309 Object.assign(this.getAttrs(), attrs); 310 return this; 311 }; 312 /** 313 * Retrieves the attributes Object (map) for the HtmlTag. 314 * 315 * @return {Object.<String, String>} A key/value object of the attributes for the HtmlTag. 316 */ 317 HtmlTag.prototype.getAttrs = function () { 318 return this.attrs; 319 }; 320 /** 321 * Sets the provided `cssClass`, overwriting any current CSS classes on the HtmlTag. 322 * 323 * @param {String} cssClass One or more space-separated CSS classes to set (overwrite). 324 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. 325 */ 326 HtmlTag.prototype.setClass = function (cssClass) { 327 return this.setAttr('class', cssClass); 328 }; 329 /** 330 * Convenience method to add one or more CSS classes to the HtmlTag. Will not add duplicate CSS classes. 331 * 332 * @param {String} cssClass One or more space-separated CSS classes to add. 333 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. 334 */ 335 HtmlTag.prototype.addClass = function (cssClass) { 336 var classAttr = this.getClass(); 337 var classes = !classAttr ? [] : classAttr.split(whitespaceRe); 338 var newClasses = cssClass.split(whitespaceRe); 339 var newClass; 340 while ((newClass = newClasses.shift())) { 341 if (classes.indexOf(newClass) === -1) { 342 classes.push(newClass); 343 } 344 } 345 this.getAttrs()['class'] = classes.join(' '); 346 return this; 347 }; 348 /** 349 * Convenience method to remove one or more CSS classes from the HtmlTag. 350 * 351 * @param {String} cssClass One or more space-separated CSS classes to remove. 352 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. 353 */ 354 HtmlTag.prototype.removeClass = function (cssClass) { 355 var classAttr = this.getClass(); 356 var classes = !classAttr ? [] : classAttr.split(whitespaceRe); 357 var removeClasses = cssClass.split(whitespaceRe); 358 var removeClass; 359 while (classes.length && (removeClass = removeClasses.shift())) { 360 var idx = classes.indexOf(removeClass); 361 if (idx !== -1) { 362 classes.splice(idx, 1); 363 } 364 } 365 this.getAttrs()['class'] = classes.join(' '); 366 return this; 367 }; 368 /** 369 * Convenience method to retrieve the CSS class(es) for the HtmlTag, which will each be separated by spaces when 370 * there are multiple. 371 * 372 * @return {String} 373 */ 374 HtmlTag.prototype.getClass = function () { 375 return this.getAttrs()['class'] || ''; 376 }; 377 /** 378 * Convenience method to check if the tag has a CSS class or not. 379 * 380 * @param {String} cssClass The CSS class to check for. 381 * @return {Boolean} `true` if the HtmlTag has the CSS class, `false` otherwise. 382 */ 383 HtmlTag.prototype.hasClass = function (cssClass) { 384 return (' ' + this.getClass() + ' ').indexOf(' ' + cssClass + ' ') !== -1; 385 }; 386 /** 387 * Sets the inner HTML for the tag. 388 * 389 * @param {String} html The inner HTML to set. 390 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. 391 */ 392 HtmlTag.prototype.setInnerHTML = function (html) { 393 this.innerHTML = html; 394 return this; 395 }; 396 /** 397 * Backwards compatibility method name. 398 * 399 * @param {String} html The inner HTML to set. 400 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. 401 */ 402 HtmlTag.prototype.setInnerHtml = function (html) { 403 return this.setInnerHTML(html); 404 }; 405 /** 406 * Retrieves the inner HTML for the tag. 407 * 408 * @return {String} 409 */ 410 HtmlTag.prototype.getInnerHTML = function () { 411 return this.innerHTML || ''; 412 }; 413 /** 414 * Backward compatibility method name. 415 * 416 * @return {String} 417 */ 418 HtmlTag.prototype.getInnerHtml = function () { 419 return this.getInnerHTML(); 420 }; 421 /** 422 * Generates the HTML string for the tag. 423 * 424 * @return {String} 425 */ 426 HtmlTag.prototype.toAnchorString = function () { 427 var tagName = this.getTagName(); 428 var attrsStr = this.buildAttrsStr(); 429 attrsStr = attrsStr ? ' ' + attrsStr : ''; // prepend a space if there are actually attributes 430 return ['<', tagName, attrsStr, '>', this.getInnerHtml(), '</', tagName, '>'].join(''); 431 }; 432 /** 433 * Support method for {@link #toAnchorString}, returns the string space-separated key="value" pairs, used to populate 434 * the stringified HtmlTag. 435 * 436 * @protected 437 * @return {String} Example return: `attr1="value1" attr2="value2"` 438 */ 439 HtmlTag.prototype.buildAttrsStr = function () { 440 var attrs = this.getAttrs(), attrsArr = []; 441 for (var prop in attrs) { 442 if (hasOwnProperty.call(attrs, prop)) { 443 attrsArr.push(prop + '="' + attrs[prop] + '"'); 444 } 445 } 446 return attrsArr.join(' '); 447 }; 448 return HtmlTag; 449}());
vendor: 10,436 bytes, lines 450-730
450 451/** 452 * Date: 2015-10-05 453 * Author: Kasper Søfren <[email protected]> (https://github.com/kafoso) 454 * 455 * A truncation feature, where the ellipsis will be placed at a section within 456 * the URL making it still somewhat human readable. 457 * 458 * @param {String} url A URL. 459 * @param {Number} truncateLen The maximum length of the truncated output URL string. 460 * @param {String} ellipsisChars The characters to place within the url, e.g. "...". 461 * @return {String} The truncated URL. 462 */ 463function truncateSmart(url, truncateLen, ellipsisChars) { 464 var ellipsisLengthBeforeParsing; 465 var ellipsisLength; 466 if (ellipsisChars == null) { 467 ellipsisChars = '…'; 468 ellipsisLength = 3; 469 ellipsisLengthBeforeParsing = 8; 470 } 471 else { 472 ellipsisLength = ellipsisChars.length; 473 ellipsisLengthBeforeParsing = ellipsisChars.length; 474 } 475 // If the URL is shorter than the truncate length, return it as is 476 if (url.length <= truncateLen) { 477 return url; 478 } 479 var availableLength = truncateLen - ellipsisLength; 480 var urlObj = parseUrl(url); 481 // Clean up the URL by removing any malformed query string 482 // (e.g. "?foo=bar?ignorethis") 483 if (urlObj.query) { 484 var matchQuery = urlObj.query.match(/^(.*?)(?=(\?|#))(.*?)$/i); 485 if (matchQuery) { 486 // Malformed URL; two or more "?". Removed any content behind the 2nd. 487 urlObj.query = urlObj.query.substr(0, matchQuery[1].length); 488 url = buildUrl(urlObj); 489 } 490 } 491 if (url.length <= truncateLen) { 492 return url; // removing a malformed query string brought the URL under the truncateLength 493 } 494 // Clean up the URL by removing 'www.' from the host if it exists 495 if (urlObj.host) { 496 urlObj.host = urlObj.host.replace(/^www\./, ''); 497 url = buildUrl(urlObj); 498 } 499 if (url.length <= truncateLen) { 500 return url; // removing 'www.' brought the URL under the truncateLength 501 } 502 // Process and build the truncated URL, starting with the hostname 503 var truncatedUrl = ''; 504 if (urlObj.host) { 505 truncatedUrl += urlObj.host; 506 } 507 if (truncatedUrl.length >= availableLength) { 508 if (urlObj.host.length === truncateLen) { 509 return (urlObj.host.substr(0, truncateLen - ellipsisLength) + ellipsisChars).substr(0, availableLength + ellipsisLengthBeforeParsing); 510 } 511 return buildSegment(truncatedUrl, availableLength, ellipsisChars).substr(0, availableLength + ellipsisLengthBeforeParsing); 512 } 513 // If we still have available chars left, add the path and query string 514 var pathAndQuery = ''; 515 if (urlObj.path) { 516 pathAndQuery += '/' + urlObj.path; 517 } 518 if (urlObj.query) { 519 pathAndQuery += '?' + urlObj.query; 520 } 521 if (pathAndQuery) { 522 if ((truncatedUrl + pathAndQuery).length >= availableLength) { 523 if ((truncatedUrl + pathAndQuery).length == truncateLen) { 524 return (truncatedUrl + pathAndQuery).substr(0, truncateLen); 525 } 526 var remainingAvailableLength = availableLength - truncatedUrl.length; 527 return (truncatedUrl + buildSegment(pathAndQuery, remainingAvailableLength, ellipsisChars)).substr(0, availableLength + ellipsisLengthBeforeParsing); 528 } 529 else { 530 truncatedUrl += pathAndQuery; 531 } 532 } 533 // If we still have available chars left, add the fragment 534 if (urlObj.fragment) { 535 var fragment = '#' + urlObj.fragment; 536 if ((truncatedUrl + fragment).length >= availableLength) { 537 if ((truncatedUrl + fragment).length == truncateLen) { 538 return (truncatedUrl + fragment).substr(0, truncateLen); 539 } 540 var remainingAvailableLength2 = availableLength - truncatedUrl.length; 541 return (truncatedUrl + buildSegment(fragment, remainingAvailableLength2, ellipsisChars)).substr(0, availableLength + ellipsisLengthBeforeParsing); 542 } 543 else { 544 truncatedUrl += fragment; 545 } 546 } 547 // If we still have available chars left, add the scheme 548 if (urlObj.scheme && urlObj.host) { 549 var scheme = urlObj.scheme + '://'; 550 if ((truncatedUrl + scheme).length < availableLength) { 551 return (scheme + truncatedUrl).substr(0, truncateLen); 552 } 553 } 554 if (truncatedUrl.length <= truncateLen) { 555 return truncatedUrl; 556 } 557 var end = ''; 558 if (availableLength > 0) { 559 end = truncatedUrl.substr(-1 * Math.floor(availableLength / 2)); 560 } 561 return (truncatedUrl.substr(0, Math.ceil(availableLength / 2)) + ellipsisChars + end).substr(0, availableLength + ellipsisLengthBeforeParsing); 562} 563/** 564 * Parses a URL into its components: scheme, host, path, query, and fragment. 565 */ 566function parseUrl(url) { 567 // Functionality inspired by PHP function of same name 568 var urlObj = {}; 569 var urlSub = url; 570 // Parse scheme 571 var match = urlSub.match(/^([a-z]+):\/\//i); 572 if (match) { 573 urlObj.scheme = match[1]; 574 urlSub = urlSub.slice(match[0].length); 575 } 576 // Parse host 577 match = urlSub.match(/^(.*?)(?=(\?|#|\/|$))/i); 578 if (match) { 579 urlObj.host = match[1]; 580 urlSub = urlSub.slice(match[0].length); 581 } 582 // Parse path 583 match = urlSub.match(/^\/(.*?)(?=(\?|#|$))/i); 584 if (match) { 585 urlObj.path = match[1]; 586 urlSub = urlSub.slice(match[0].length); 587 } 588 // Parse query 589 match = urlSub.match(/^\?(.*?)(?=(#|$))/i); 590 if (match) { 591 urlObj.query = match[1]; 592 urlSub = urlSub.slice(match[0].length); 593 } 594 // Parse fragment 595 match = urlSub.match(/^#(.*?)$/i); 596 if (match) { 597 urlObj.fragment = match[1]; 598 //urlSub = urlSub.slice(match[0].length); -- not used. Uncomment if adding another block. 599 } 600 return urlObj; 601} 602function buildUrl(urlObj) { 603 var url = ''; 604 if (urlObj.scheme && urlObj.host) { 605 url += urlObj.scheme + '://'; 606 } 607 if (urlObj.host) { 608 url += urlObj.host; 609 } 610 if (urlObj.path) { 611 url += '/' + urlObj.path; 612 } 613 if (urlObj.query) { 614 url += '?' + urlObj.query; 615 } 616 if (urlObj.fragment) { 617 url += '#' + urlObj.fragment; 618 } 619 return url; 620} 621function buildSegment(segment, remainingAvailableLength, ellipsisChars) { 622 var remainingAvailableLengthHalf = remainingAvailableLength / 2; 623 var startOffset = Math.ceil(remainingAvailableLengthHalf); 624 var endOffset = -1 * Math.floor(remainingAvailableLengthHalf); 625 var end = ''; 626 if (endOffset < 0) { 627 end = segment.substr(endOffset); 628 } 629 return segment.substr(0, startOffset) + ellipsisChars + end; 630} 631 632/** 633 * Date: 2015-10-05 634 * Author: Kasper Søfren <[email protected]> (https://github.com/kafoso) 635 * 636 * A truncation feature, where the ellipsis will be placed in the dead-center of the URL. 637 * 638 * @param {String} url A URL. 639 * @param {Number} truncateLen The maximum length of the truncated output URL string. 640 * @param {String} ellipsisChars The characters to place within the url, e.g. "..". 641 * @return {String} The truncated URL. 642 */ 643function truncateMiddle(url, truncateLen, ellipsisChars) { 644 if (url.length <= truncateLen) { 645 return url; 646 } 647 var ellipsisLengthBeforeParsing; 648 var ellipsisLength; 649 if (ellipsisChars == null) { 650 ellipsisChars = '…'; 651 ellipsisLengthBeforeParsing = 8; 652 ellipsisLength = 3; 653 } 654 else { 655 ellipsisLengthBeforeParsing = ellipsisChars.length; 656 ellipsisLength = ellipsisChars.length; 657 } 658 var availableLength = truncateLen - ellipsisLength; 659 var end = ''; 660 if (availableLength > 0) { 661 end = url.substr(-1 * Math.floor(availableLength / 2)); 662 } 663 return (url.substr(0, Math.ceil(availableLength / 2)) + ellipsisChars + end).substr(0, availableLength + ellipsisLengthBeforeParsing); 664} 665 666/** 667 * A truncation feature where the ellipsis will be placed at the end of the URL. 668 * 669 * @param {String} anchorText 670 * @param {Number} truncateLen The maximum length of the truncated output URL string. 671 * @param {String} ellipsisChars The characters to place within the url, e.g. "..". 672 * @return {String} The truncated URL. 673 */ 674function truncateEnd(anchorText, truncateLen, ellipsisChars) { 675 return ellipsis(anchorText, truncateLen, ellipsisChars); 676} 677 678/** 679 * @protected 680 * @class Autolinker.AnchorTagBuilder 681 * @extends Object 682 * 683 * Builds anchor (<a>) tags for the Autolinker utility when a match is 684 * found. 685 * 686 * Normally this class is instantiated, configured, and used internally by an 687 * {@link Autolinker} instance, but may actually be used indirectly in a 688 * {@link Autolinker#replaceFn replaceFn} to create {@link Autolinker.HtmlTag HtmlTag} 689 * instances which may be modified before returning from the 690 * {@link Autolinker#replaceFn replaceFn}. For example: 691 * 692 * var html = Autolinker.link("Test google.com", { 693 * replaceFn: function(match) { 694 * var tag = match.buildTag(); // returns an {@link Autolinker.HtmlTag} instance 695 * tag.setAttr('rel', 'nofollow'); 696 * 697 * return tag; 698 * } 699 * }); 700 * 701 * // generated html: 702 * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a> 703 */ 704var AnchorTagBuilder = /** @class */ (function () { 705 /** 706 * @method constructor 707 * @param {Object} [cfg] The configuration options for the AnchorTagBuilder instance, specified in an Object (map). 708 */ 709 function AnchorTagBuilder(cfg) { 710 if (cfg === void 0) { cfg = {}; } 711 /** 712 * @cfg {Boolean} newWindow 713 * @inheritdoc Autolinker#newWindow 714 */ 715 this.newWindow = false; // default value just to get the above doc comment in the ES5 output and documentation generator 716 /** 717 * @cfg {Object} truncate 718 * @inheritdoc Autolinker#truncate 719 */ 720 this.truncate = {}; // default value just to get the above doc comment in the ES5 output and documentation generator 721 /** 722 * @cfg {String} className 723 * @inheritdoc Autolinker#className 724 */ 725 this.className = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 726 this.newWindow = cfg.newWindow || false; 727 this.truncate = cfg.truncate || {}; 728 this.className = cfg.className || ''; 729 } 730 /**
731 * Generates the actual anchor (<a>) tag to use in place of the 732 * matched text, via its `match` object. 733 * 734 * @param match The Match instance to generate an anchor tag from. 735 * @return The HtmlTag instance for the anchor tag. 736 */ 737 AnchorTagBuilder.prototype.build = function (match) { 738 return new HtmlTag({ 739 tagName: 'a', 740 attrs: this.createAttrs(match), 741 innerHtml: this.processAnchorText(match.getAnchorText()), 742 }); 743 }; 744 /** 745 * Creates the Object (map) of the HTML attributes for the anchor (<a>) 746 * tag being generated. 747 * 748 * @protected 749 * @param match The Match instance to generate an anchor tag from. 750 * @return A key/value Object (map) of the anchor tag's attributes. 751 */ 752 AnchorTagBuilder.prototype.createAttrs = function (match) { 753 var attrs = { 754 href: match.getAnchorHref(), // we'll always have the `href` attribute 755 }; 756 var cssClass = this.createCssClass(match); 757 if (cssClass) { 758 attrs['class'] = cssClass; 759 } 760 if (this.newWindow) { 761 attrs['target'] = '_blank'; 762 attrs['rel'] = 'noopener noreferrer'; // Issue #149. See https://mathiasbynens.github.io/rel-noopener/ 763 } 764 if (this.truncate.length && this.truncate.length < match.getAnchorText().length) { 765 attrs['title'] = match.getAnchorHref(); 766 } 767 return attrs; 768 }; 769 /** 770 * Creates the CSS class that will be used for a given anchor tag, based on 771 * the `matchType` and the {@link #className} config. 772 * 773 * Example returns: 774 * 775 * - "" // no {@link #className} 776 * - "myLink myLink-url" // url match 777 * - "myLink myLink-email" // email match 778 * - "myLink myLink-phone" // phone match 779 * - "myLink myLink-hashtag" // hashtag match 780 * - "myLink myLink-mention myLink-twitter" // mention match with Twitter service 781 * 782 * @protected 783 * @param match The Match instance to generate an 784 * anchor tag from. 785 * @return The CSS class string for the link. Example return: 786 * "myLink myLink-url". If no {@link #className} was configured, returns 787 * an empty string. 788 */ 789 AnchorTagBuilder.prototype.createCssClass = function (match) { 790 var className = this.className; 791 if (!className) { 792 return ''; 793 } 794 else { 795 var returnClasses = [className], cssClassSuffixes = match.getCssClassSuffixes(); 796 for (var i = 0, len = cssClassSuffixes.length; i < len; i++) { 797 returnClasses.push(className + '-' + cssClassSuffixes[i]); 798 } 799 return returnClasses.join(' '); 800 } 801 }; 802 /** 803 * Processes the `anchorText` by truncating the text according to the 804 * {@link #truncate} config. 805 * 806 * @private 807 * @param anchorText The anchor tag's text (i.e. what will be 808 * displayed). 809 * @return The processed `anchorText`. 810 */ 811 AnchorTagBuilder.prototype.processAnchorText = function (anchorText) { 812 anchorText = this.doTruncate(anchorText); 813 return anchorText; 814 }; 815 /** 816 * Performs the truncation of the `anchorText` based on the {@link #truncate} 817 * option. If the `anchorText` is longer than the length specified by the 818 * {@link #truncate} option, the truncation is performed based on the 819 * `location` property. See {@link #truncate} for details. 820 * 821 * @private 822 * @param anchorText The anchor tag's text (i.e. what will be 823 * displayed). 824 * @return The truncated anchor text. 825 */ 826 AnchorTagBuilder.prototype.doTruncate = function (anchorText) { 827 var truncate = this.truncate; 828 if (!truncate.length) 829 return anchorText; 830 var truncateLength = truncate.length, truncateLocation = truncate.location; 831 if (truncateLocation === 'smart') { 832 return truncateSmart(anchorText, truncateLength); 833 } 834 else if (truncateLocation === 'middle') { 835 return truncateMiddle(anchorText, truncateLength); 836 } 837 else { 838 return truncateEnd(anchorText, truncateLength); 839 } 840 }; 841 return AnchorTagBuilder; 842}()); 843 844/** 845 * @abstract 846 * @class Autolinker.match.AbstractMatch 847 * 848 * Represents a match found in an input string which should be Autolinked. A Match object is what is provided in a 849 * {@link Autolinker#replaceFn replaceFn}, and may be used to query for details about the match. 850 * 851 * For example: 852 * 853 * var input = "..."; // string with URLs, Email Addresses, and Mentions (Twitter, Instagram, Soundcloud) 854 * 855 * var linkedText = Autolinker.link( input, { 856 * replaceFn : function( match ) { 857 * console.log( "href = ", match.getAnchorHref() ); 858 * console.log( "text = ", match.getAnchorText() ); 859 * 860 * switch( match.getType() ) { 861 * case 'url' : 862 * console.log( "url: ", match.getUrl() ); 863 * 864 * case 'email' : 865 * console.log( "email: ", match.getEmail() ); 866 * 867 * case 'mention' : 868 * console.log( "mention: ", match.getMention() ); 869 * } 870 * } 871 * } ); 872 * 873 * See the {@link Autolinker} class for more details on using the {@link Autolinker#replaceFn replaceFn}. 874 */ 875var AbstractMatch = /** @class */ (function () { 876 /** 877 * @member Autolinker.match.Match 878 * @method constructor 879 * @param {Object} cfg The configuration properties for the Match 880 * instance, specified in an Object (map). 881 */ 882 function AbstractMatch(cfg) { 883 /** 884 * @cfg {Autolinker.AnchorTagBuilder} tagBuilder (required) 885 * 886 * Reference to the AnchorTagBuilder instance to use to generate an anchor 887 * tag for the Match. 888 */ 889 // @ts-expect-error Property used just to get the above doc comment into the ES5 output and documentation generator 890 this._ = null; 891 /** 892 * @cfg {String} matchedText (required) 893 * 894 * The original text that was matched by the {@link Autolinker.matcher.Matcher}. 895 */ 896 this.matchedText = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 897 /** 898 * @cfg {Number} offset (required) 899 * 900 * The offset of where the match was made in the input string. 901 */ 902 this.offset = 0; // default value just to get the above doc comment in the ES5 output and documentation generator 903 this.tagBuilder = cfg.tagBuilder; 904 this.matchedText = cfg.matchedText; 905 this.offset = cfg.offset; 906 } 907 /** 908 * Returns the original text that was matched. 909 * 910 * @return {String} 911 */ 912 AbstractMatch.prototype.getMatchedText = function () { 913 return this.matchedText; 914 }; 915 /** 916 * Sets the {@link #offset} of where the match was made in the input string. 917 * 918 * A {@link Autolinker.matcher.Matcher} will be fed only HTML text nodes, 919 * and will therefore set an original offset that is relative to the HTML 920 * text node itself. However, we want this offset to be relative to the full 921 * HTML input string, and thus if using {@link Autolinker#parse} (rather 922 * than calling a {@link Autolinker.matcher.Matcher} directly), then this 923 * offset is corrected after the Matcher itself has done its job. 924 * 925 * @private 926 * @param {Number} offset 927 */ 928 AbstractMatch.prototype.setOffset = function (offset) { 929 this.offset = offset; 930 }; 931 /** 932 * Returns the offset of where the match was made in the input string. This 933 * is the 0-based index of the match. 934 * 935 * @return {Number} 936 */ 937 AbstractMatch.prototype.getOffset = function () { 938 return this.offset; 939 }; 940 /** 941 * Returns the CSS class suffix(es) for this match. 942 *
943 * A CSS class suffix is appended to the {@link Autolinker#className} in 944 * the {@link Autolinker.AnchorTagBuilder} when a match is translated into 945 * an anchor tag. 946 * 947 * For example, if {@link Autolinker#className} was configured as 'myLink', 948 * and this method returns `[ 'url' ]`, the final class name of the element 949 * will become: 'myLink myLink-url'. 950 * 951 * The match may provide multiple CSS class suffixes to be appended to the 952 * {@link Autolinker#className} in order to facilitate better styling 953 * options for different match criteria. See {@link Autolinker.match.Mention} 954 * for an example. 955 * 956 * By default, this method returns a single array with the match's 957 * {@link #getType type} name, but may be overridden by subclasses. 958 * 959 * @return {String[]} 960 */ 961 AbstractMatch.prototype.getCssClassSuffixes = function () { 962 return [this.type]; 963 }; 964 /** 965 * Builds and returns an {@link Autolinker.HtmlTag} instance based on the 966 * Match. 967 * 968 * This can be used to easily generate anchor tags from matches, and either 969 * return their HTML string, or modify them before doing so. 970 * 971 * Example Usage: 972 * 973 * var tag = match.buildTag(); 974 * tag.addClass( 'cordova-link' ); 975 * tag.setAttr( 'target', '_system' ); 976 * 977 * tag.toAnchorString(); // <a href="http://google.com" class="cordova-link" target="_system">Google</a> 978 * 979 * Example Usage in {@link Autolinker#replaceFn}: 980 * 981 * var html = Autolinker.link( "Test google.com", { 982 * replaceFn : function( match ) { 983 * var tag = match.buildTag(); // returns an {@link Autolinker.HtmlTag} instance 984 * tag.setAttr( 'rel', 'nofollow' ); 985 * 986 * return tag; 987 * } 988 * } ); 989 * 990 * // generated html: 991 * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a> 992 */ 993 AbstractMatch.prototype.buildTag = function () { 994 return this.tagBuilder.build(this); 995 }; 996 return AbstractMatch; 997}()); 998 999// NOTE: THIS FILE IS GENERATED. DO NOT EDIT. 1000// INSTEAD, RUN: npm run generate-char-utils 1001/** 1002 * Determines if the given character `c` matches the regular expression /[\x00-\x1F\x7F]/ 1003 * by checking it via character code in a binary search fashion. 1004 * 1005 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1006 * on the character itself. 1007 * 1008 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1009 * 1010 * npm run generate-char-utils 1011 */ 1012function isControlChar(c) { 1013 return ((c >= 0 && c <= 31) || c == 127); 1014} 1015/** 1016 * Determines if the given character `c` matches the regular expression /[A-Za-z]/ 1017 * by checking it via character code in a binary search fashion. 1018 * 1019 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1020 * on the character itself. 1021 * 1022 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1023 * 1024 * npm run generate-char-utils 1025 */ 1026function isAsciiLetterChar(c) { 1027 return ((c >= 65 && c <= 90) || (c >= 97 && c <= 122)); 1028} 1029/** 1030 * Determines if the given character `c` matches the regular expression /\d/ 1031 * by checking it via character code in a binary search fashion. 1032 * 1033 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1034 * on the character itself. 1035 * 1036 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1037 * 1038 * npm run generate-char-utils 1039 */ 1040function isDigitChar(c) { 1041 return (c >= 48 && c <= 57); 1042} 1043/** 1044 * Determines if the given character `c` matches the regular expression /['"]/ 1045 * by checking it via character code in a binary search fashion. 1046 * 1047 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1048 * on the character itself. 1049 * 1050 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1051 * 1052 * npm run generate-char-utils 1053 */ 1054function isQuoteChar(c) { 1055 return (c == 34 || c == 39); 1056} 1057/** 1058 * Determines if the given character `c` matches the regular expression /\s/ 1059 * by checking it via character code in a binary search fashion. 1060 * 1061 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1062 * on the character itself. 1063 * 1064 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1065 * 1066 * npm run generate-char-utils 1067 */ 1068function isWhitespaceChar(c) { 1069 return (c < 8232 ? (c < 160 ? ((c >= 9 && c <= 13) || c == 32) : (c < 5760 ? c == 160 : (c == 5760 || (c >= 8192 && c <= 8202)))) : (c < 8287 ? ((c >= 8232 && c <= 8233) || c == 8239) : (c < 12288 ? c == 8287 : (c == 12288 || c == 65279)))
1069); 1070} 1071/** 1072 * Determines if the given character `c` matches the regular expression /[A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFB
1072D3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC\u2700-\u27bf\udde6-\uddff\ud800-\udbff\udc00-\udfff\ufe0e\ufe0f\u0300-\u036f\ufe20-\ufe23\u20d0-\u20f0\ud83c\udffb-\udfff\u200d\u3299\u3297\u303d\u3030\u24c2\ud83c\udd70-\udd71\udd7e-\udd7f\udd8e\udd91-\udd9a\udde6-\uddff\ude01-\ude02\ude1a\ude2f\ude32-\ude3a\ude50-\ude51\u203c\u2049\u25aa-\u25ab\u25b6\u25c0\u25fb-\u25fe\u00a9\u00ae\u2122\u2139\udc04\u2600-\u26FF\u2b05\u2b06\u2b07\u2b1b\u2b1c\u2b50\u2b55\u231a\u231b\u2328\u23cf\u23e9-\u23f3\u23f8-\u23fa\udccf\u2935\u2934\u2190-\u21ff\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D4-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D01-\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF8\u1CF9\u1DC0-\u1DF5\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F0-9\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19]/ 1073 * by checking it via character code in a binary search fashion. 1074 * 1075 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1076 * on the character itself. 1077 * 1078 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1079 * 1080 * npm run generate-char-utils 1081 */
vendor: 15,635 bytes, lines 1082-1095
1082function isAlphaNumericOrMarkChar(c) { 1083 return (c < 4800 ? (c < 2949 ? (c < 2451 ? (c < 1425 ? (c < 768 ? (c < 192 ? (c < 169 ? (c < 65 ? (c >= 48 && c <= 57) : ((c >= 65 && c <= 90) || (c >= 97 && c <= 122))) : (c < 181 ? ((c >= 169 && c <= 170) || c == 174) : (c == 181 || c == 186))) : (c < 710 ? (c < 216 ? (c >= 192 && c <= 214) : ((c >= 216 && c <= 246) || (c >= 248 && c <= 705))) : (c < 748 ? ((c >= 710 && c <= 721) || (c >= 736 && c <= 740)) : (c == 748 || c == 750)))) : (c < 910 ? (c < 895 ? (c < 886 ? (c >= 768 && c <= 884) : ((c >= 886 && c <= 887) || (c >= 890 && c <= 893))) : (c < 904 ? (c == 895 || c == 902) : ((c >= 904 && c <= 906) || c == 908))) : (c < 1155 ? (c < 931 ? (c >= 910 && c <= 929) : ((c >= 931 && c <= 1013) || (c >= 1015 && c <= 1153))) : (c < 1369 ? ((c >= 1155 && c <= 1327) || (c >= 1329 && c <= 1366)) : (c == 1369 || (c >= 1377 && c <= 1415)))))) : (c < 1808 ? (c < 1552 ? (c < 1476 ? (c < 1471 ? (c >= 1425 && c <= 1469) : (c == 1471 || (c >= 1473 && c <= 1474))) : (c < 1488 ? ((c >= 1476 && c <= 1477) || c == 1479) : ((c >= 1488 && c <= 1514) || (c >= 1520 && c <= 1522)))) : (c < 1749 ? (c < 1568 ? (c >= 1552 && c <= 1562) : ((c >= 1568 && c <= 1641) || (c >= 1646 && c <= 1747))) : (c < 1770 ? ((c >= 1749 && c <= 1756) || (c >= 1759 && c <= 1768)) : ((c >= 1770 && c <= 1788) || c == 1791)))) : (c < 2230 ? (c < 2042 ? (c < 1869 ? (c >= 1808 && c <= 1866) : ((c >= 1869 && c <= 1969) || (c >= 1984 && c <= 2037))) : (c < 2112 ? (c == 2042 || (c >= 2048 && c <= 2093)) : ((c >= 2112 && c <= 2139) || (c >= 2208 && c <= 2228)))) : (c < 2406 ? (c < 2260 ? (c >= 2230 && c <= 2237) : ((c >= 2260 && c <= 2273) || (c >= 2275 && c <= 2403))) : (c < 2437 ? ((c >= 2406 && c <= 2415) || (c >= 2417 && c <= 2435)) : ((c >= 2437 && c <= 2444) || (c >= 2447 && c <= 2448))))))) : (c < 2693 ? (c < 2579 ? (c < 2519 ? (c < 2486 ? (c < 2474 ? (c >= 2451 && c <= 2472) : ((c >= 2474 && c <= 2480) || c == 2482)) : (c < 2503 ? ((c >= 2486 && c <= 2489) || (c >= 2492 && c <= 2500)) : ((c >= 2503 && c <= 2504) || (c >= 2507 && c <= 2510)))) : (c < 2534 ? (c < 2524 ? c == 2519 : ((c >= 2524 && c <= 2525) || (c >= 2527 && c <= 2531))) : (c < 2565 ? ((c >= 2534 && c <= 2545) || (c >= 2561 && c <= 2563)) : ((c >= 2565 && c <= 2570) || (c >= 2575 && c <= 2576))))) : (c < 2631 ? (c < 2613 ? (c < 2602 ? (c >= 2579 && c <= 2600) : ((c >= 2602 && c <= 2608) || (c >= 2610 && c <= 2611))) : (c < 2620 ? ((c >= 2613 && c <= 2614) || (c >= 2616 && c <= 2617)) : (c == 2620 || (c >= 2622 && c <= 2626)))) : (c < 2649 ? (c < 2635 ? (c >= 2631 && c <= 2632) : ((c >= 2635 && c <= 2637) || c == 2641)) : (c < 2662 ? ((c >= 2649 && c <= 2652) || c == 2654) : ((c >= 2662 && c <= 2677) || (c >= 2689 && c <= 2691)))))) : (c < 2821 ? (c < 2759 ? (c < 2730 ? (c < 2703 ? (c >= 2693 && c <= 2701) : ((c >= 2703 && c <= 2705) || (c >= 2707 && c <= 2728))) : (c < 2741 ? ((c >= 2730 && c <= 2736) || (c >= 2738 && c <= 2739)) : ((c >= 2741 && c <= 2745) || (c >= 2748 && c <= 2757)))) : (c < 2784 ? (c < 2763 ? (c >= 2759 && c <= 2761) : ((c >= 2763 && c <= 2765) || c == 2768)) : (c < 2809 ? ((c >= 2784 && c <= 2787) || (c >= 2790 && c <= 2799)) : (c == 2809 || (c >= 2817 && c <= 2819))))) : (c < 2887 ? (c < 2858 ? (c < 2831 ? (c >= 2821 && c <= 2828) : ((c >= 2831 && c <= 2832) || (c >= 2835 && c <= 2856))) : (c < 2869 ? ((c >= 2858 && c <= 2864) || (c >= 2866 && c <= 2867)) : ((c >= 2869 && c <= 2873) || (c >= 2876 && c <= 2884)))) : (c < 2911 ? (c < 2902 ? ((c >= 2887 && c <= 2888) || (c >= 2891 && c <= 2893)) : ((c >= 2902 && c <= 2903) || (c >= 2908 && c <= 2909))) : (c < 2929 ? ((c >= 2911 && c <= 2915) || (c >= 2918 && c <= 2927)) : (c == 2929 || (c >= 2946 && c <= 2947)))))))) : (c < 3517 ? (c < 3205 ? (c < 3046 ? (c < 2984 ? (c < 2969 ? (c < 2958 ? (c >= 2949 && c <= 2954) : ((c >= 2958 && c <= 2960) || (c >= 2962 && c <= 2965))) : (c < 2974 ? ((c >= 2969 && c <= 2970) || c == 2972) : ((c >= 2974 && c <= 2975) || (c >= 2979 && c <= 2980)))) : (c < 3014 ? (c < 2990 ? (c >= 2984 && c <= 2986) : ((c >= 2990 && c <= 3001) || (c >= 3006 && c <= 3010))) : (c < 3024 ? ((c >= 3014 && c <= 3016) || (c >= 3018 && c <= 3021)) : (c == 3024 || c == 3031)))) : (c < 3142 ? (c < 3086 ? (c < 3072 ? (c >= 3046 && c <= 3055) : ((c >= 3072 && c <= 3075) || (c >= 3077 && c <= 3084))) : (c < 3114 ? ((c >= 3086 && c <= 3088) || (c >= 3090 && c <= 3112)) : ((c >= 3114 && c <= 3129) || (c >= 3133 && c <= 3140)))) : (c < 3160 ? (c < 3146 ? (c >= 3142 && c <= 3144) : ((c >= 3146 && c <= 3149) || (c >= 3157 && c <= 3158))) : (c < 3174 ? ((c >= 3160 && c <= 3162) || (c >= 3168 && c <= 3171)) : ((c >= 3174 && c <= 3183) || (c >= 3200 && c <= 3203)))))) : (c < 3333 ? (c < 3274 ? (c < 3242 ? (c < 3214 ? (c >= 3205 && c <= 3212) : ((c >= 3214 && c <= 3216) || (c >= 3218 && c <= 3240))) : (c < 3260 ? ((c >= 3242 && c <= 3251) || (c >= 3253 && c <= 3257)) : ((c >= 3260 && c <= 3268) || (c >= 3270 && c <= 3272)))) : (c < 3296 ? (c < 3285 ? (c >= 3274 && c <= 3277) : ((c >= 3285 && c <= 3286) || c == 3294)) : (c < 3313 ? ((c >= 3296 && c <= 3299) || (c >= 3302 && c <= 3311)) : ((c >= 3313 && c <= 3314) || (c >= 3329 && c <= 3331))))) : (c < 3423 ? (c < 3389 ? (c < 3342 ? (c >= 3333 && c <= 3340) : ((c >= 3342 && c <= 3344) || (c >= 3346 && c <= 3386))) : (c < 3402 ? ((c >= 3389 && c <= 3396) || (c >= 3398 && c <= 3400)) : ((c >= 3402 && c <= 3406) || (c >= 3412 && c <= 3415)))) : (c < 3458 ? (c < 3430 ? (c >= 3423 && c <= 3427) : ((c >= 3430 && c <= 3439) || (c >= 3450 && c <= 3455))) : (c < 3482 ? ((c >= 3458 && c <= 3459) || (c >= 3461 && c <= 3478)) : ((c >= 3482 && c <= 3505) || (c >= 3507 && c <= 3515))))))) : (c < 3804 ? (c < 3722 ? (c < 3570 ? (c < 3535 ? (c < 3520 ? c == 3517 : ((c >= 3520 && c <= 3526) || c == 3530)) : (c < 3544 ? ((c >= 3535 && c <= 3540) || c == 3542) : ((c >= 3544 && c <= 3551) || (c >= 3558 && c <= 3567)))) : (c < 3664 ? (c < 3585 ? (c >= 3570 && c <= 3571) : ((c >= 3585 && c <= 3642) || (c >= 3648 && c <= 3662))) : (c < 3716 ? ((c >= 3664 && c <= 3673) || (c >= 3713 && c <= 3714)) : (c == 3716 || (c >= 3719 && c <= 3720))))) : (c < 3754 ? (c < 3737 ? (c < 3725 ? c == 3722 : (c == 3725 || (c >= 3732 && c <= 3735))) : (c < 3749 ? ((c >= 3737 && c <= 3743) || (c >= 3745 && c <= 3747)) : (c == 3749 || c == 3751))) : (c < 3776 ? (c < 3757 ? (c >= 3754 && c <= 3755) : ((c >= 3757 && c <= 3769) || (c >= 3771 && c <= 3773))) : (c < 3784 ? ((c >= 3776 && c <= 3780) || c == 3782) : ((c >= 3784 && c <= 3789) || (c >= 3792 && c <= 3801)))))) : (c < 4176 ? (c < 3902 ? (c < 3872 ? (c < 3840 ? (c >= 3804 && c <= 3807) : (c == 3840 || (c >= 3864 && c <= 3865))) : (c < 3895 ? ((c >= 3872 && c <= 3881) || c == 3893) : (c == 3895 || c == 3897))) : (c < 3974 ? (c < 3913 ? (c >= 3902 && c <= 3911) : ((c >= 3913 && c <= 3948) || (c >= 3953 && c <= 3972))) : (c < 4038 ? ((c >= 3974 && c <= 3991) || (c >= 3993 && c <= 4028)) : (c == 4038 || (c >= 4096 && c <= 4169))))) : (c < 4688 ? (c < 4301 ? (c < 4256 ? (c >= 4176 && c <= 4253) : ((c >= 4256 && c <= 4293) || c == 4295)) : (c < 4348 ? (c == 4301 || (c >= 4304 && c <= 4346)) : ((c >= 4348 && c <= 4680) || (c >= 4682 && c <= 4685)))) : (c < 4746 ? (c < 4698 ? ((c >= 4688 && c <= 4694) || c == 4696) : ((c >= 4698 && c <= 4701) || (c >= 4704 && c <= 4744))) : (c < 4786 ? ((c >= 4746 && c <= 4749) || (c >= 4752 && c <= 4784)) : ((c >= 4786 && c <= 4789) || (c >= 4792 && c <= 4798))))))))) : (c < 11035 ? (c < 7416 ? (c < 6176 ? (c < 5873 ? (c < 4992 ? (c < 4824 ? (c < 4802 ? c == 4800 : ((c >= 4802 && c <= 4805) || (c >= 4808 && c <= 4822))) : (c < 4888 ? ((c >= 4824 && c <= 4880) || (c >= 4882 && c <= 4885)) : ((c >= 4888 && c <= 4954) || (c >= 4957 && c <= 4959)))) : (c < 5121 ? (c < 5024 ? (c >= 4992 && c <= 5007) : ((c >= 5024 && c <= 5109) || (c >= 5112 && c <= 5117))) : (c < 5761 ? ((c >= 5121 && c <= 5740) || (c >= 5743 && c <= 5759)) : ((c >= 5761 && c <= 5786) || (c >= 5792 && c <= 5866))))) : (c < 6002 ? (c < 5920 ? (c < 5888 ? (c >= 5873 && c <= 5880) : ((c >= 5888 && c <= 5900) || (c >= 5902 && c <= 5908))) : (c < 5984 ? ((c >= 5920 && c <= 5940) || (c >= 5952 && c <= 5971)) : ((c >= 5984 && c <= 5996) || (c >= 5998 && c <= 6000)))) : (c < 6108 ? (c < 6016 ? (c >= 6002 && c <= 6003) : ((c >= 6016 && c <= 6099) || c == 6103)) : (c < 6155 ? ((c >= 6108 && c <= 6109) || (c >= 6112 && c <= 6121)) : ((c >= 6155 && c <= 6157) || (c >= 6160 && c <= 6169)))))) : (c < 6783 ? (c < 6512 ? (c < 6400 ? (c < 6272 ? (c >= 6176 && c <= 6263) : ((c >= 6272 && c <= 6314) || (c >= 6320 && c <= 6389))) : (c < 6448 ? ((c >= 6400 && c <= 6430) || (c >= 6432 && c <= 6443)) : ((c >= 6448 && c <= 6459) || (c >= 6470 && c <= 6509)))) : (c < 6608 ? (c < 6528 ? (c >= 6512 && c <= 6516) : ((c >= 6528 && c <= 6571) || (c >= 6576 && c <= 6601))) : (c < 6688 ? ((c >= 6608 && c <= 6617) || (c >= 6656 && c <= 6683)) : ((c >= 6688 && c <= 6750) || (c >= 6752 && c <= 6780))))) : (c < 7040 ? (c < 6832 ? (c < 6800 ? (c >= 6783 && c <= 6793) : ((c >= 6800 && c <= 6809) || c == 6823)) : (c < 6992 ? ((c >= 6832 && c <= 6846) || (c >= 6912 && c <= 6987)) : ((c >= 6992 && c <= 7001) || (c >= 7019 && c <= 7027)))) : (c < 7245 ? (c < 7168 ? (c >= 7040 && c <= 7155) : ((c >= 7168 && c <= 7223) || (c >= 7232 && c <= 7241))) : (c < 7376 ? ((c >= 7245 && c <= 7293) || (c >= 7296 && c <= 7304)) : ((c >= 7376 && c <= 7378) || (c >= 7380 && c <= 7414))))))) : (c < 8450 ? (c < 8130 ? (c < 8025 ? (c < 7960 ? (c < 7424 ? (c >= 7416 && c <= 7417) : ((c >= 7424 && c <= 7669) || (c >= 7675 && c <= 7957))) : (c < 8008 ? ((c >= 7960 && c <= 7965) || (c >= 7968 && c <= 8005)) : ((c >= 8008 && c <= 8013) || (c >= 8016 && c <= 8023)))) : (c < 8031 ? (c < 8027 ? c == 8025 : (c == 8027 || c == 8029)) : (c < 8118 ? ((c >= 8031 && c <= 8061) || (c >= 8064 && c <= 8116)) : ((c >= 8118 && c <= 8124) || c == 8126)))) : (c < 8205 ? (c < 8150 ? (c < 8134 ? (c >= 8130 && c <= 8132) : ((c >= 8134 && c <= 8140) || (c >= 8144 && c <= 8147))) : (c < 8178 ? ((c >= 8150 && c <= 8155) || (c >= 8160 && c <= 8172)) : ((c >= 8178 && c <= 8180) || (c >= 8182 && c <= 8188)))) : (c < 8305 ? (c < 8252 ? c == 8205 : (c == 8252 || c == 8265)) : (c < 8336 ? (c == 8305 || c == 8319) : ((c >= 8336 && c <= 8348) || (c >= 8400 && c <= 8432)))))) : (c < 8579 ? (c < 8486 ? (c < 8469 ? (c < 8455 ? c == 8450 : (c == 8455 || (c >= 8458 && c <= 8467))) : (c < 8482 ? (c == 8469 || (c >= 8473 && c <= 8477)) : (c == 8482 || c == 8484))) : (c < 8495 ? (c < 8488 ? c == 8486 : (c == 8488 || (c >= 8490 && c <= 8493))) : (c < 8517 ? ((c >= 8495 && c <= 8505) || (c >= 8508 && c <= 8511)) : ((c >= 8517 && c <= 8521) || c == 8526)))) : (c < 9410 ? (c < 9000 ? (c < 8592 ? (c >= 8579 && c <= 8580) : ((c >= 8592 && c <= 8703) || (c >= 8986 && c <= 8987))) : (c < 9193 ? (c == 9000 || c == 9167) : ((c >= 9193 && c <= 9203) || (c >= 9208 && c <= 9210)))) : (c < 9723 ? (c < 9654 ? (c == 9410 || (c >= 9642 && c <= 9643)) : (c == 9654 || c == 9664)) : (c < 10548 ? ((c >= 9723 && c <= 9726) || (c >= 9728 && c <= 10175)) : ((c >= 10548 && c <= 10549) || (c >= 11013 && c <= 11015)))))))) : (c < 43259 ? (c < 12445 ? (c < 11688 ? (c < 11520 ? (c < 11264 ? (c < 11088 ? (c >= 11035 && c <= 11036) : (c == 11088 || c == 11093)) : (c < 11360 ? ((c >= 11264 && c <= 11310) || (c >= 11312 && c <= 11358)) : ((c >= 11360 && c <= 11492) || (c >= 11499 && c <= 11507)))) : (c < 11568 ? (c < 11559 ? (c >= 11520 && c <= 11557) : (c == 11559 || c == 11565)) : (c < 11647 ? ((c >= 11568 && c <= 11623) || c == 11631) : ((c >= 11647 && c <= 11670) || (c >= 11680 && c <= 11686))))) : (c < 11744 ? (c < 11712 ? (c < 11696 ? (c >= 11688 && c <= 11694) : ((c >= 11696 && c <= 11702) || (c >= 11704 && c <= 11710))) : (c < 11728 ? ((c >= 11712 && c <= 11718) || (c >= 11720 && c <= 11726)) : ((c >= 11728 && c <= 11734) || (c >= 11736 && c <= 11742)))) : (c < 12330 ? (c < 11823 ? (c >= 11744 && c <= 11775) : (c == 11823 || (c >= 12293 && c <= 12294))) : (c < 12353 ? ((c >= 12330 && c <= 12341) || (c >= 12347 && c <= 12349)) : ((c >= 12353 && c <= 12438) || (c >= 12441 && c <= 12442)))))) : (c < 42512 ? (c < 12951 ? (c < 12549 ? (c < 12449 ? (c >= 12445 && c <= 12447) : ((c >= 12449 && c <= 12538) || (c >= 12540 && c <= 12543))) : (c < 12704 ? ((c >= 12549 && c <= 12589) || (c >= 12593 && c <= 12686)) : ((c >= 12704 && c <= 12730) || (c >= 12784 && c <= 12799)))) : (c < 19968 ? (c < 12953 ? c == 12951 : (c == 12953 || (c >= 13312 && c <= 19893))) : (c < 42192 ? ((c >= 19968 && c <= 40917) || (c >= 40960 && c <= 42124)) : ((c >= 42192 && c <= 42237) || (c >= 42240 && c <= 42508))))) : (c < 42891 ? (c < 42623 ? (c < 42560 ? (c >= 42512 && c <= 42539) : ((c >= 42560 && c <= 42610) || (c >= 42612 && c <= 42621))) : (c < 42775 ? ((c >= 42623 && c <= 42725) || (c >= 42736 && c <= 42737)) : ((c >= 42775 && c <= 42783) || (c >= 42786 && c <= 42888)))) : (c < 43072 ? (c < 42928 ? (c >= 42891 && c <= 42926) : ((c >= 42928 && c <= 42935) || (c >= 42999 && c <= 43047))) : (c < 43216 ? ((c >= 43072 && c <= 43123) || (c >= 43136 && c <= 43205)) : ((c >= 43216 && c <= 43225) || (c >= 43232 && c <= 43255))))))) : (c < 55243 ? (c < 43744 ? (c < 43488 ? (c < 43312 ? (c < 43261 ? c == 43259 : (c == 43261 || (c >= 43264 && c <= 43309))) : (c < 43392 ? ((c >= 43312 && c <= 43347) || (c >= 43360 && c <= 43388)) : ((c >= 43392 && c <= 43456) || (c >= 43471 && c <= 43481)))) : (c < 43600 ? (c < 43520 ? (c >= 43488 && c <= 43518) : ((c >= 43520 && c <= 43574) || (c >= 43584 && c <= 43597))) : (c < 43642 ? ((c >= 43600 && c <= 43609) || (c >= 43616 && c <= 43638)) : ((c >= 43642 && c <= 43714) || (c >= 43739 && c <= 43741))))) : (c < 43824 ? (c < 43785 ? (c < 43762 ? (c >= 43744 && c <= 43759) : ((c >= 43762 && c <= 43766) || (c >= 43777 && c <= 43782))) : (c < 43808 ? ((c >= 43785 && c <= 43790) || (c >= 43793 && c <= 43798)) : ((c >= 43808 && c <= 43814) || (c >= 43816 && c <= 43822)))) : (c < 44012 ? (c < 43868 ? (c >= 43824 && c <= 43866) : ((c >= 43868 && c <= 43877) || (c >= 43888 && c <= 44010))) : (c < 44032 ? ((c >= 44012 && c <= 44013) || (c >= 44016 && c <= 44025)) : ((c >= 44032 && c <= 55203) || (c >= 55216 && c <= 55238)))))) : (c < 64848 ? (c < 64298 ? (c < 64112 ? (c < 55296 ? (c >= 55243 && c <= 55291) : ((c >= 55296 && c <= 57343) || (c >= 63744 && c <= 64109))) : (c < 64275 ? ((c >= 64112 && c <= 64217) || (c >= 64256 && c <= 64262)) : ((c >= 64275 && c <= 64279) || (c >= 64285 && c <= 64296)))) : (c < 64320 ? (c < 64312 ? (c >= 64298 && c <= 64310) : ((c >= 64312 && c <= 64316) || c == 64318)) : (c < 64326 ? ((c >= 64320 && c <= 64321) || (c >= 64323 && c <= 64324)) : ((c >= 64326 && c <= 64433) || (c >= 64467 && c <= 64829))))) : (c < 65296 ? (c < 65024 ? (c < 64914 ? (c >= 64848 && c <= 64911) : ((c >= 64914 && c <= 64967) || (c >= 65008 && c <= 65019))) : (c < 65136 ? ((c >= 65024 && c <= 65039) || (c >= 65056 && c <= 65071)) : ((c >= 65136 && c <= 65140) || (c >= 65142 && c <= 65276)))) : (c < 65474 ? (c < 65345 ? ((c >= 65296 && c <= 65305) || (c >= 65313 && c <= 65338)) : ((c >= 65345 && c <= 65370) || (c >= 65382 && c <= 65470))) : (c < 65490 ? ((c >= 65474 && c <= 65479) || (c >= 65482 && c <= 65487)) : ((c >= 65490 && c <= 65495) || (c >= 65498 && c <= 65500)))))))))); 1084} 1085/** 1086 * Determines if the given character `c` matches the regular expression /[!#$%&'*+/=?^_`{|}~-]/ 1087 * by checking it via character code in a binary search fashion. 1088 * 1089 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1090 * on the character itself. 1091 * 1092 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1093 * 1094 * npm run generate-char-utils 1095 */
vendor: 2,618 bytes, lines 1096-1158
1096function isValidEmailLocalPartSpecialChar(c) { 1097 return (c < 47 ? (c < 42 ? (c == 33 || (c >= 35 && c <= 39)) : ((c >= 42 && c <= 43) || c == 45)) : (c < 63 ? (c == 47 || c == 61) : (c < 94 ? c == 63 : ((c >= 94 && c <= 96) || (c >= 123 && c <= 126))))); 1098} 1099/** 1100 * Determines if the given character `c` matches the regular expression /[-+&@#/%=~_()|'$*[\]{}\u2713]/ 1101 * by checking it via character code in a binary search fashion. 1102 * 1103 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1104 * on the character itself. 1105 * 1106 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1107 * 1108 * npm run generate-char-utils 1109 */ 1110function isUrlSuffixAllowedSpecialChar(c) { 1111 return (c < 91 ? (c < 47 ? ((c >= 35 && c <= 43) || c == 45) : (c < 61 ? c == 47 : (c == 61 || c == 64))) : (c < 95 ? (c == 91 || c == 93) : (c < 123 ? c == 95 : ((c >= 123 && c <= 126) || c == 10003)))); 1112} 1113/** 1114 * Determines if the given character `c` matches the regular expression /[?!:,.;^]/ 1115 * by checking it via character code in a binary search fashion. 1116 * 1117 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1118 * on the character itself. 1119 * 1120 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1121 * 1122 * npm run generate-char-utils 1123 */ 1124function isUrlSuffixNotAllowedAsFinalChar(c) { 1125 return (c < 58 ? (c < 44 ? c == 33 : (c == 44 || c == 46)) : (c < 63 ? (c >= 58 && c <= 59) : (c == 63 || c == 94))); 1126} 1127/** 1128 * Determines if the given character `c` matches the regular expression /[({[]/ 1129 * by checking it via character code in a binary search fashion. 1130 * 1131 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1132 * on the character itself. 1133 * 1134 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1135 * 1136 * npm run generate-char-utils 1137 */ 1138function isOpenBraceChar(c) { 1139 return (c < 91 ? c == 40 : (c == 91 || c == 123)); 1140} 1141/** 1142 * Determines if the given character `c` matches the regular expression /[)}\]]/ 1143 * by checking it via character code in a binary search fashion. 1144 * 1145 * This technique speeds this function up by a factor of ~10x vs. running RegExp.prototype.test() 1146 * on the character itself. 1147 * 1148 * NOTE: This function is generated. Do not edit manually. To regenerate, run: 1149 * 1150 * npm run generate-char-utils 1151 */ 1152function isCloseBraceChar(c) { 1153 return (c < 93 ? c == 41 : (c == 93 || c == 125)); 1154} 1155 1156// NOTE: THIS IS A GENERATED FILE 1157// To update with the latest TLD list, run `npm run update-known-tlds` 1158var tldRegex =
vendor: 1,969 bytes, line 1158
1158/^(?:xn--vermgensberatung-pwb|xn--vermgensberater-ctb|xn--clchc0ea0b2g2a9gcd|xn--w4r85el8fhu5dnra|travelersinsurance|vermögensberatung|xn--5su34j936bgsg|xn--bck1b9a5dre4c|xn--mgbah1a3hjkrd|xn--mgbai9azgqp6j|xn--mgberp4a5d4ar|xn--xkc2dl3a5ee0h|vermögensberater|xn--fzys8d69uvgm|xn--mgba7c0bbn0a|xn--mgbcpq6gpa1a|xn--xkc2al3hye2a|americanexpress|kerryproperties|sandvikcoromant|xn--i1b6b1a6a2e|xn--kcrx77d1x4a|xn--lgbbat1ad8j|xn--mgba3a4f16a|xn--mgbc0a9azcg|xn--nqv7fs00ema|americanfamily|weatherchannel|xn--54b7fta0cc|xn--6qq986b3xl|xn--80aqecdr1a|xn--b4w605ferd|xn--fiq228c5hs|xn--h2breg3eve|xn--jlq480n2rg|xn--mgba3a3ejt|xn--mgbaam7a8h|xn--mgbayh7gpa|xn--mgbbh1a71e|xn--mgbca7dzdo|xn--mgbi4ecexp|xn--mgbx4cd0ab|xn--rvc1e0am3e|international|lifeinsurance|wolterskluwer|xn--cckwcxetd|xn--eckvdtc9d|xn--fpcrj9c3d|xn--fzc2c9e2c|xn--h2brj9c8c|xn--tiq49xqyj|xn--yfro4i67o|xn--ygbi2ammx|construction|lplfinancial|scholarships|versicherung|xn--3e0b707e|xn--45br5cyl|xn--4dbrk0ce|xn--80adxhks|xn--80asehdb|xn--8y0a063a|xn--gckr3f0f|xn--mgb9awbf|xn--mgbab2bd|xn--mgbgu82a|xn--mgbpl2fh|xn--mgbt3dhd|xn--mk1bu44c|xn--ngbc5azd|xn--ngbe9e0a|xn--ogbpf8fl|xn--qcka1pmc|accountants|barclaycard|blackfriday|blockbuster|bridgestone|calvinklein|contractors|creditunion|engineering|enterprises|investments|kerryhotels|lamborghini|motorcycles|olayangroup|photography|playstation|productions|progressive|redumbrella|williamhill|xn--11b4c3d|xn--1ck2e1b|xn--1qqw23a|xn--2scrj9c|xn--3bst00m|xn--3ds443g|xn--3hcrj9c|xn--42c2d9a|xn--45brj9c|xn--55qw42g|xn--6frz82g|xn--80ao21a|xn--9krt00a|xn--cck2b3b|xn--czr694b|xn--d1acj3b|xn--efvy88h|xn--fct429k|xn--fjq720a|xn--flw351e|xn--g2xx48c|xn--gecrj9c|xn--gk3at1e|xn--h2brj9c|xn--hxt814e|xn--imr513n|xn--j6w193g|xn--jvr189m|xn--kprw13d|xn--kpry57d|xn--mgbbh1a|xn--mgbtx2b|xn--mix891f|xn--nyqy26a|xn--otu796d|xn--pgbs0dh|xn--q9jyb4c|xn--rhqv96g|xn--rovu88b|xn--s9brj9c|xn--ses554g|xn--t60b56a|xn--vuq861b|xn--w4rs40l|xn--xhq521b|xn--zfr164b|à®à®¿à®
vendor: 9,053 bytes, line 1158
1158à¯à®à®ªà¯à®ªà¯à®°à¯|accountant|apartments|associates|basketball|bnpparibas|boehringer|capitalone|consulting|creditcard|cuisinella|eurovision|extraspace|foundation|healthcare|immobilien|industries|management|mitsubishi|nextdirect|properties|protection|prudential|realestate|republican|restaurant|schaeffler|tatamotors|technology|university|vlaanderen|xn--30rr7y|xn--3pxu8k|xn--45q11c|xn--4gbrim|xn--55qx5d|xn--5tzm5g|xn--80aswg|xn--90a3ac|xn--9dbq2a|xn--9et52u|xn--c2br7g|xn--cg4bki|xn--czrs0t|xn--czru2d|xn--fiq64b|xn--fiqs8s|xn--fiqz9s|xn--io0a7i|xn--kput3i|xn--mxtq1m|xn--o3cw4h|xn--pssy2u|xn--q7ce6a|xn--unup4y|xn--wgbh1c|xn--wgbl6a|xn--y9a3aq|accenture|allfinanz|amsterdam|analytics|aquarelle|barcelona|bloomberg|christmas|community|directory|education|equipment|fairwinds|financial|firestone|fresenius|furniture|goldpoint|hisamitsu|homedepot|homegoods|homesense|institute|insurance|kuokgroup|landrover|lifestyle|marketing|marshalls|melbourne|microsoft|panasonic|pramerica|richardli|shangrila|solutions|statebank|statefarm|stockholm|travelers|vacations|xn--90ais|xn--c1avg|xn--d1alf|xn--e1a4c|xn--fhbei|xn--j1aef|xn--j1amh|xn--l1acc|xn--ngbrx|xn--nqv7f|xn--p1acf|xn--qxa6a|xn--tckwe|xn--vhquv|yodobashi|Ù
ÙØ±ÙتاÙÙØ§|abudhabi|airforce|allstate|attorney|barclays|barefoot|bargains|baseball|boutique|bradesco|broadway|brussels|builders|business|capetown|catering|catholic|cipriani|cleaning|clinique|clothing|commbank|computer|delivery|deloitte|democrat|diamonds|discount|discover|download|engineer|ericsson|exchange|feedback|fidelity|firmdale|football|frontier|goodyear|grainger|graphics|hdfcbank|helsinki|holdings|hospital|infiniti|ipiranga|istanbul|jpmorgan|lighting|lundbeck|marriott|mckinsey|memorial|merckmsd|mortgage|observer|partners|pharmacy|pictures|plumbing|property|redstone|reliance|saarland|samsclub|security|services|shopping|softbank|software|stcgroup|supplies|training|vanguard|ventures|verisign|woodside|xn--90ae|xn--node|xn--p1ai|xn--qxam|yokohama|Ø§ÙØ³Ø¹ÙØ¯ÙØ©|abogado|academy|agakhan|alibaba|android|athleta|auction|audible|auspost|banamex|bauhaus|bestbuy|booking|brother|capital|caravan|careers|channel|charity|chintai|citadel|clubmed|college|cologne|company|compare|contact|cooking|corsica|country|coupons|courses|cricket|cruises|dentist|digital|domains|exposed|express|farmers|fashion|ferrari|ferrero|finance|fishing|fitness|flights|florist|flowers|forsale|frogans|fujitsu|gallery|genting|godaddy|grocery|guitars|hamburg|hangout|hitachi|holiday|hosting|hotmail|hyundai|ismaili|jewelry|juniper|kitchen|komatsu|lacaixa|lanxess|lasalle|latrobe|leclerc|limited|lincoln|markets|monster|netbank|netflix|network|neustar|okinawa|organic|origins|philips|pioneer|politie|realtor|recipes|rentals|reviews|rexroth|samsung|sandvik|schmidt|schwarz|science|shiksha|singles|staples|storage|support|surgery|systems|temasek|theater|theatre|tickets|toshiba|trading|walmart|wanggou|watches|weather|website|wedding|whoswho|windows|winners|yamaxun|youtube|zuerich|каÑолик|Ø§ÙØ¨ØØ±ÙÙ|Ø§ÙØ¬Ø²Ø§Ø¦Ø±|Ø§ÙØ¹ÙÙØ§Ù|پاکستاÙ|ÙØ§Ø«ÙÙÙÙ|à®à®¨à¯à®¤à®¿à®¯à®¾|abbott|abbvie|africa|agency|airbus|airtel|alipay|alsace|alstom|amazon|anquan|aramco|author|bayern|beauty|berlin|bharti|bostik|boston|broker|camera|career|casino|center|chanel|chrome|church|circle|claims|clinic|coffee|comsec|condos|coupon|credit|cruise|dating|datsun|dealer|degree|dental|design|direct|doctor|dunlop|dupont|durban|emerck|energy|estate|events|expert|family|flickr|futbol|gallup|garden|george|giving|global|google|gratis|health|hermes|hiphop|hockey|hotels|hughes|imamat|insure|intuit|jaguar|joburg|juegos|kaufen|kindle|kosher|latino|lawyer|lefrak|living|locker|london|luxury|madrid|maison|makeup|market|mattel|mobile|monash|mormon|moscow|museum|nagoya|nissan|nissay|norton|nowruz|office|olayan|online|oracle|orange|otsuka|pfizer|photos|physio|pictet|quebec|racing|realty|reisen|repair|report|review|rogers|ryukyu|safety|sakura|sanofi|school|schule|search|secure|select|shouji|soccer|social|stream|studio|supply|suzuki|swatch|sydney|taipei|taobao|target|tattoo|tennis|tienda|tjmaxx|tkmaxx|toyota|travel|unicom|viajes|viking|villas|virgin|vision|voting|voyage|walter|webcam|xihuan|yachts|yandex|zappos|моÑква|онлайн|Ø§Ø¨ÙØ¸Ø¨Ù|اراÙ
ÙÙ|Ø§ÙØ§Ø±Ø¯Ù|اÙÙ
غرب|اÙ
ارات|ÙÙØ³Ø·ÙÙ|Ù
ÙÙØ³Ùا|à¤à¤¾à¤°à¤¤à¤®à¥|à®à®²à®à¯à®à¯|ãã¡ãã·ã§ã³|actor|adult|aetna|amfam|amica|apple|archi|audio|autos|azure|baidu|beats|bible|bingo|black|boats|bosch|build|canon|cards|chase|cheap|cisco|citic|click|cloud|coach|codes|crown|cymru|dance|deals|delta|drive|dubai|earth|edeka|email|epson|faith|fedex|final|forex|forum|gallo|games|gifts|gives|glass|globo|gmail|green|gripe|group|gucci|guide|homes|honda|horse|house|hyatt|ikano|irish|jetzt|koeln|kyoto|lamer|lease|legal|lexus|lilly|loans|locus|lotte|lotto|mango|media|miami|money|movie|music|nexus|nikon|ninja|nokia|nowtv|omega|osaka|paris|parts|party|phone|photo|pizza|place|poker|praxi|press|prime|promo|quest|radio|rehab|reise|ricoh|rocks|rodeo|rugby|salon|sener|seven|sharp|shell|shoes|skype|sling|smart|smile|solar|space|sport|stada|store|study|style|sucks|swiss|tatar|tires|tirol|tmall|today|tokyo|tools|toray|total|tours|trade|trust|tunes|tushu|ubank|vegas|video|vodka|volvo|wales|watch|weber|weibo|works|world|xerox|yahoo|×שר××|Ø§ÛØ±Ø§Ù|بازار|بھارت|Ø³ÙØ¯Ø§Ù|Ø³ÙØ±ÙØ©|ÙÙ
راÙ|à¤à¤¾à¤°à¥à¤¤|सà¤à¤à¤ न|বাà¦à¦²à¦¾|à°à°¾à°°à°¤à±|à´à´¾à´°à´¤à´|åé大é
åº|aarp|able|aero|akdn|ally|amex|arab|army|arpa|arte|asda|asia|audi|auto|baby|band|bank|bbva|beer|best|bike|bing|blog|blue|bofa|bond|book|buzz|cafe|call|camp|care|cars|casa|case|cash|cbre|cern|chat|citi|city|club|cool|coop|cyou|data|date|dclk|deal|dell|desi|diet|dish|docs|dvag|erni|fage|fail|fans|farm|fast|fido|film|fire|fish|flir|food|ford|free|fund|game|gbiz|gent|ggee|gift|gmbh|gold|golf|goog|guge|guru|hair|haus|hdfc|help|here|host|hsbc|icbc|ieee|imdb|immo|info|itau|java|jeep|jobs|jprs|kddi|kids|kiwi|kpmg|kred|land|lego|lgbt|lidl|life|like|limo|link|live|loan|love|ltda|luxe|maif|meet|meme|menu|mini|mint|mobi|moda|moto|name|navy|news|next|nico|nike|ollo|open|page|pars|pccw|pics|ping|pink|play|plus|pohl|porn|post|prod|prof|qpon|read|reit|rent|rest|rich|room|rsvp|ruhr|safe|sale|sarl|save|saxo|scot|seat|seek|sexy|shia|shop|show|silk|sina|site|skin|sncf|sohu|song|sony|spot|star|surf|talk|taxi|team|tech|teva|tiaa|tips|town|toys|tube|vana|visa|viva|vivo|vote|voto|wang|weir|wien|wiki|wine|work|xbox|yoga|zara|zero|zone|деÑи|ÑайÑ|بارت|Ø¨ÙØªÙ|ÚØ§Ø±Øª|تÙÙØ³|Ø´Ø¨ÙØ©|عراÙ|عÙ
اÙ|Ù
ÙÙØ¹|à¤à¤¾à¤°à¤¤|à¦à¦¾à¦°à¦¤|à¦à¦¾à§°à¦¤|à¨à¨¾à¨°à¨¤|àªàª¾àª°àª¤|à¬à¬¾à¬°à¬¤|à²à²¾à²°à²¤|à¶½à¶à¶à·|ã¢ãã¾ã³|ã°ã¼ã°ã«|ã¯ã©ã¦ã|ãã¤ã³ã|ç»ç»æºæ|é»è¨çç§|馿 ¼éæ|aaa|abb|abc|aco|ads|aeg|afl|aig|anz|aol|app|art|aws|axa|bar|bbc|bbt|bcg|bcn|bet|bid|bio|biz|bms|bmw|bom|boo|bot|box|buy|bzh|cab|cal|cam|car|cat|cba|cbn|ceo|cfa|cfd|com|cpa|crs|dad|day|dds|dev|dhl|diy|dnp|dog|dot|dtv|dvr|eat|eco|edu|esq|eus|fan|fit|fly|foo|fox|frl|ftr|fun|fyi|gal|gap|gay|gdn|gea|gle|gmo|gmx|goo|gop|got|gov|hbo|hiv|hkt|hot|how|ibm|ice|icu|ifm|inc|ing|ink|int|ist|itv|jcb|jio|jll|jmp|jnj|jot|joy|kfh|kia|kim|kpn|krd|lat|law|lds|llc|llp|lol|lpl|ltd|man|map|mba|med|men|mil|mit|mlb|mls|mma|moe|moi|mom|mov|msd|mtn|mtr|nab|nba|nec|net|new|nfl|ngo|nhk|now|nra|nrw|ntt|nyc|obi|one|ong|onl|ooo|org|ott|ovh|pay|pet|phd|pid|pin|pnc|pro|pru|pub|pwc|red|ren|ril|rio|rip|run|rwe|sap|sas|sbi|sbs|scb|sew|sex|sfr|ski|sky|soy|spa|srl|stc|tab|tax|tci|tdk|tel|thd|tjx|top|trv|tui|tvs|ubs|uno|uol|ups|vet|vig|vin|vip|wed|win|wme|wow|wtc|wtf|xin|xxx|xyz|you|yun|zip|бел|ком|Òаз|мкд|мон|оÑг|ÑÑÑ|ÑÑб|ÑкÑ|Õ°Õ¡Õµ|×§××|عرب|ÙØ·Ø±|ÙÙÙ
|Ù
صر|à¤à¥à¤®|नà¥à¤|à¸à¸à¸¡|à¹à¸à¸¢|ລາວ|ã¹ãã¢|ã»ã¼ã«|ã¿ããª|䏿ç½|äºé©¬é|天主æ|æç±ä½ |æ°å å¡|淡马é¡|é£å©æµ¦|ac|ad|ae|af|ag|ai|al|am|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cw|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw|ελ|εÏ
|бг|еÑ|ÑÑ|áá|ë·ë·|ë·ì»´|ì¼ì±|íêµ|ã³ã |ä¸ç|ä¸ä¿¡|ä¸å½|ä¸å|ä¼ä¸|ä½å±±|ä¿¡æ¯|å¥åº·|å
«å¦|å
¬å¸|å
¬ç|å°æ¹¾|å°ç£|åå|ååº|åæ |åé|å¨çº¿|大æ¿|娱ä¹|å®¶é»|广ä¸|å¾®å|æ
å|ææº|æè|æ¿å¡|æ¿åº|æ°é»|æ¶å°|æ¸ç±|æºæ|游æ|æ¾³é|ç¹ç|ç§»å¨|ç½å|ç½åº|ç½ç«|ç½ç»|èé|è°·æ|è´ç©|é販|éå¢|é£å|é¤å
|馿¸¯)$/
vendor: 8,947 bytes, lines 1158-1393
1158; 1159 1160/** 1161 * Regular expression to match an http:// or https:// scheme. 1162 */ 1163var httpSchemeRe = /https?:\/\//i; 1164/** 1165 * Regular expression to match an http:// or https:// scheme as the prefix of 1166 * a string. 1167 */ 1168var httpSchemePrefixRe = new RegExp('^' + httpSchemeRe.source, 'i'); 1169/** 1170 * A regular expression used to determine the schemes we should not autolink 1171 */ 1172var invalidSchemeRe = /^(javascript|vbscript):/i; 1173// A regular expression used to determine if the URL is a scheme match (such as 1174// 'http://google.com', and as opposed to a "TLD match"). This regular 1175// expression is used to parse out the host along with if the URL has an 1176// authority component (i.e. '//') 1177// 1178// Capturing groups: 1179// 1. '//' if the URL has an authority component, empty string otherwise 1180// 2. The host (if one exists). Ex: 'google.com' 1181// 1182// See https://www.rfc-editor.org/rfc/rfc3986#appendix-A for terminology 1183var schemeUrlRe = /^[A-Za-z][-.+A-Za-z0-9]*:(\/\/)?([^:/]*)/; 1184// A regular expression used to determine if the URL is a TLD match (such as 1185// 'google.com', and as opposed to a "scheme match"). This regular 1186// expression is used to help parse out the TLD (top-level domain) of the host. 1187// 1188// See https://www.rfc-editor.org/rfc/rfc3986#appendix-A for terminology 1189var tldUrlHostRe = /^(?:\/\/)?([^/#?:]+)/; // optionally prefixed with protocol-relative '//' chars 1190/** 1191 * Determines if the given character code represents a character that may start 1192 * a scheme (ex: the 'h' in 'http') 1193 */ 1194var isSchemeStartChar = isAsciiLetterChar; // Equivalent to checking the RegExp `/[A-Za-z]/`, but aliased for clarity and maintainability 1195/** 1196 * Determines if the given character is a valid character in a scheme (such as 1197 * 'http' or 'ssh+git'), but only after the start char (which is handled by 1198 * {@link isSchemeStartChar}. 1199 */ 1200function isSchemeChar(charCode) { 1201 return (isAsciiLetterChar(charCode) || 1202 isDigitChar(charCode) || 1203 charCode === 43 /* Char.Plus */ || // '+' 1204 charCode === 45 /* Char.Dash */ || // '-' 1205 charCode === 46 /* Char.Dot */ // '.' 1206 ); 1207} 1208/** 1209 * Determines if the character can begin a domain label, which must be an 1210 * alphanumeric character and not an underscore or dash. 1211 * 1212 * A domain label is a segment of a hostname such as subdomain.google.com. 1213 */ 1214var isDomainLabelStartChar = isAlphaNumericOrMarkChar; // alias function for clarity 1215/** 1216 * Determines if the character is part of a domain label (but not a domain label 1217 * start character). 1218 * 1219 * A domain label is a segment of a hostname such as subdomain.google.com. 1220 */ 1221function isDomainLabelChar(charCode) { 1222 return charCode === 95 /* Char.Underscore */ || isDomainLabelStartChar(charCode); 1223} 1224/** 1225 * Determines if the character is a path character ("pchar") as defined by 1226 * https://tools.ietf.org/html/rfc3986#appendix-A 1227 * 1228 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 1229 * 1230 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 1231 * pct-encoded = "%" HEXDIG HEXDIG 1232 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" 1233 * / "*" / "+" / "," / ";" / "=" 1234 * 1235 * Note that this implementation doesn't follow the spec exactly, but rather 1236 * follows URL path characters found out in the wild (spec might be out of date?) 1237 */ 1238function isPathChar(charCode) { 1239 return (isAlphaNumericOrMarkChar(charCode) || 1240 isUrlSuffixAllowedSpecialChar(charCode) || 1241 isUrlSuffixNotAllowedAsFinalChar(charCode) // characters in addition to those allowed by isUrlSuffixAllowedSpecialChar() 1242 ); 1243} 1244/** 1245 * Determines if the character given may begin the "URL Suffix" section of a 1246 * URI (i.e. the path, query, or hash section). These are the '/', '?' and '#' 1247 * characters. 1248 * 1249 * See https://tools.ietf.org/html/rfc3986#appendix-A 1250 */ 1251function isUrlSuffixStartChar(charCode) { 1252 return (charCode === 47 /* Char.Slash */ || // '/' 1253 charCode === 63 /* Char.Question */ || // '?' 1254 charCode === 35 /* Char.NumberSign */ // '#' 1255 ); 1256} 1257/** 1258 * Determines if the top-level domain (TLD) read in the host is a known TLD. 1259 * 1260 * Example: 'com' would be a known TLD (for a host of 'google.com'), but 1261 * 'local' would not (for a domain name of 'my-computer.local'). 1262 */ 1263function isKnownTld(tld) { 1264 return tldRegex.test(tld.toLowerCase()); // make sure the tld is lowercase for the regex 1265} 1266/** 1267 * Determines if the given `url` is a valid scheme-prefixed URL. 1268 */ 1269function isValidSchemeUrl(url) { 1270 // If the scheme is 'javascript:' or 'vbscript:', these link 1271 // types can be dangerous. Don't link them. 1272 if (invalidSchemeRe.test(url)) { 1273 return false; 1274 } 1275 var schemeMatch = url.match(schemeUrlRe); 1276 if (!schemeMatch) { 1277 return false; 1278 } 1279 var isAuthorityMatch = !!schemeMatch[1]; 1280 var host = schemeMatch[2]; 1281 if (isAuthorityMatch) { 1282 // Any match that has an authority ('//' chars) after the scheme is 1283 // valid, such as 'http://anything' 1284 return true; 1285 } 1286 // If there's no authority ('//' chars), check that we have a hostname 1287 // that looks valid. 1288 // 1289 // The host must contain at least one '.' char and have a domain label 1290 // with at least one letter to be considered valid. 1291 // 1292 // Accept: 1293 // - git:domain.com (scheme followed by a host 1294 // Do not accept: 1295 // - git:something ('something' doesn't look like a host) 1296 // - version:1.0 ('1.0' doesn't look like a host) 1297 if (host.indexOf('.') === -1 || !/[A-Za-z]/.test(host)) { 1298 // `letterRe` RegExp checks for a letter anywhere in the host string 1299 return false; 1300 } 1301 return true; 1302} 1303/** 1304 * Determines if the given `url` is a match with a valid TLD. 1305 */ 1306function isValidTldMatch(url) { 1307 // TLD URL such as 'google.com', we need to confirm that we have a valid 1308 // top-level domain 1309 var tldUrlHostMatch = url.match(tldUrlHostRe); 1310 if (!tldUrlHostMatch) { 1311 // At this point, if the URL didn't match our TLD re, it must be invalid 1312 // (highly unlikely to happen, but just in case) 1313 return false; 1314 } 1315 var host = tldUrlHostMatch[0]; 1316 var hostLabels = host.split('.'); 1317 if (hostLabels.length < 2) { 1318 // 0 or 1 host label, there's no TLD. Ex: 'localhost' 1319 return false; 1320 } 1321 var tld = hostLabels[hostLabels.length - 1]; 1322 if (!isKnownTld(tld)) { 1323 return false; 1324 } 1325 // TODO: Implement these conditions for TLD matcher: 1326 // ( 1327 // this.longestDomainLabelLength <= 63 && 1328 // this.domainNameLength <= 255 1329 // ); 1330 return true; 1331} 1332// Regular expression to confirm a valid IPv4 address (ex: '192.168.0.1') 1333// TODO: encode this into the state machine so that we don't need to run this 1334// regexp separately to confirm the match 1335var ipV4Re = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; 1336// Regular expression used to split the IPv4 address itself from any port/path/query/hash 1337var ipV4PartRe = /[:/?#]/; 1338/** 1339 * Determines if the given URL is a valid IPv4-prefixed URL. 1340 */ 1341function isValidIpV4Address(url) { 1342 // Grab just the IP address 1343 var ipV4Part = url.split(ipV4PartRe, 1)[0]; // only 1 result needed 1344 return ipV4Re.test(ipV4Part); 1345} 1346 1347/** 1348 * A regular expression used to remove the 'www.' from URLs. 1349 */ 1350var wwwPrefixRegex = /^(https?:\/\/)?(?:www\.)?/i; 1351/** 1352 * The regular expression used to remove the protocol-relative '//' from a URL 1353 * string, for purposes of formatting the anchor text. A protocol-relative URL 1354 * is, for example, "//yahoo.com" 1355 */ 1356var protocolRelativeRegex = /^\/\//; 1357/** 1358 * @class Autolinker.match.Url 1359 * @extends Autolinker.match.AbstractMatch 1360 * 1361 * Represents a Url match found in an input string which should be Autolinked. 1362 * 1363 * See this class's superclass ({@link Autolinker.match.Match}) for more details. 1364 */ 1365var UrlMatch = /** @class */ (function (_super) { 1366 __extends(UrlMatch, _super); 1367 /** 1368 * @method constructor 1369 * @param {Object} cfg The configuration properties for the Match 1370 * instance, specified in an Object (map). 1371 */ 1372 function UrlMatch(cfg) { 1373 var _this = _super.call(this, cfg) || this; 1374 /** 1375 * @public 1376 * @property {'url'} type 1377 * 1378 * A string name for the type of match that this class represents. Can be 1379 * used in a TypeScript discriminating union to type-narrow from the 1380 * `Match` type. 1381 */ 1382 _this.type = 'url'; 1383 /** 1384 * @cfg {String} url (required) 1385 * 1386 * The url that was matched. 1387 */ 1388 _this.url = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 1389 /** 1390 * @cfg {"scheme"/"www"/"tld"} urlMatchType (required) 1391 * 1392 * The type of URL match that this class represents. This helps to determine 1393 * if the match was made in the original text with a prefixed scheme (ex:
1394 * 'http://www.google.com'), a prefixed 'www' (ex: 'www.google.com'), or 1395 * was matched by a known top-level domain (ex: 'google.com'). 1396 */ 1397 _this.urlMatchType = 'scheme'; // default value just to get the above doc comment in the ES5 output and documentation generator 1398 /** 1399 * @cfg {Boolean} protocolRelativeMatch (required) 1400 * 1401 * `true` if the URL is a protocol-relative match. A protocol-relative match 1402 * is a URL that starts with '//', and will be either http:// or https:// 1403 * based on the protocol that the site is loaded under. 1404 */ 1405 _this.protocolRelativeMatch = false; // default value just to get the above doc comment in the ES5 output and documentation generator 1406 /** 1407 * @cfg {Object} stripPrefix (required) 1408 * 1409 * The Object form of {@link Autolinker#cfg-stripPrefix}. 1410 */ 1411 _this.stripPrefix = { 1412 scheme: true, 1413 www: true, 1414 }; // default value just to get the above doc comment in the ES5 output and documentation generator 1415 /** 1416 * @cfg {Boolean} stripTrailingSlash (required) 1417 * @inheritdoc Autolinker#cfg-stripTrailingSlash 1418 */ 1419 _this.stripTrailingSlash = true; // default value just to get the above doc comment in the ES5 output and documentation generator 1420 /** 1421 * @cfg {Boolean} decodePercentEncoding (required) 1422 * @inheritdoc Autolinker#cfg-decodePercentEncoding 1423 */ 1424 _this.decodePercentEncoding = true; // default value just to get the above doc comment in the ES5 output and documentation generator 1425 /** 1426 * @private 1427 * @property {Boolean} protocolPrepended 1428 * 1429 * Will be set to `true` if the 'http://' protocol has been prepended to the {@link #url} (because the 1430 * {@link #url} did not have a protocol) 1431 */ 1432 _this.protocolPrepended = false; 1433 _this.urlMatchType = cfg.urlMatchType; 1434 _this.url = cfg.url; 1435 _this.protocolRelativeMatch = cfg.protocolRelativeMatch; 1436 _this.stripPrefix = cfg.stripPrefix; 1437 _this.stripTrailingSlash = cfg.stripTrailingSlash; 1438 _this.decodePercentEncoding = cfg.decodePercentEncoding; 1439 return _this; 1440 } 1441 /** 1442 * Returns a string name for the type of match that this class represents. 1443 * For the case of UrlMatch, returns 'url'. 1444 * 1445 * @return {String} 1446 */ 1447 UrlMatch.prototype.getType = function () { 1448 return 'url'; 1449 }; 1450 /** 1451 * Returns a string name for the type of URL match that this class 1452 * represents. 1453 * 1454 * This helps to determine if the match was made in the original text with a 1455 * prefixed scheme (ex: 'http://www.google.com'), a prefixed 'www' (ex: 1456 * 'www.google.com'), or was matched by a known top-level domain (ex: 1457 * 'google.com'). 1458 * 1459 * @return {"scheme"/"www"/"tld"} 1460 */ 1461 UrlMatch.prototype.getUrlMatchType = function () { 1462 return this.urlMatchType; 1463 }; 1464 /** 1465 * Returns the url that was matched, assuming the protocol to be 'http://' if the original 1466 * match was missing a protocol. 1467 * 1468 * @return {String} 1469 */ 1470 UrlMatch.prototype.getUrl = function () { 1471 var url = this.url; 1472 // if the url string doesn't begin with a scheme, assume 'http://' 1473 if (!this.protocolRelativeMatch && 1474 this.urlMatchType !== 'scheme' && 1475 !this.protocolPrepended) { 1476 url = this.url = 'http://' + url; 1477 this.protocolPrepended = true; 1478 } 1479 return url; 1480 }; 1481 /** 1482 * Returns the anchor href that should be generated for the match. 1483 * 1484 * @return {String} 1485 */ 1486 UrlMatch.prototype.getAnchorHref = function () { 1487 var url = this.getUrl(); 1488 return url.replace(/&/g, '&'); // any &'s in the URL should be converted back to '&' if they were displayed as & in the source html 1489 }; 1490 /** 1491 * Returns the anchor text that should be generated for the match. 1492 * 1493 * @return {String} 1494 */ 1495 UrlMatch.prototype.getAnchorText = function () { 1496 var anchorText = this.getMatchedText(); 1497 if (this.protocolRelativeMatch) { 1498 // Strip off any protocol-relative '//' from the anch
1498or text 1499 anchorText = stripProtocolRelativePrefix(anchorText); 1500 } 1501 if (this.stripPrefix.scheme) { 1502 anchorText = stripSchemePrefix(anchorText); 1503 } 1504 if (this.stripPrefix.www) { 1505 anchorText = stripWwwPrefix(anchorText); 1506 } 1507 if (this.stripTrailingSlash) { 1508 anchorText = removeTrailingSlash(anchorText); // remove trailing slash, if there is one 1509 } 1510 if (this.decodePercentEncoding) { 1511 anchorText = removePercentEncoding(anchorText); 1512 } 1513 return anchorText; 1514 }; 1515 return UrlMatch; 1516}(AbstractMatch)); 1517// Utility Functionality 1518/** 1519 * Strips the scheme prefix (such as "http://" or "https://") from the given 1520 * `url`. 1521 * 1522 * @private 1523 * @param {String} url The text of the anchor that is being generated, for 1524 * which to strip off the url scheme. 1525 * @return {String} The `url`, with the scheme stripped. 1526 */ 1527function stripSchemePrefix(url) { 1528 return url.replace(httpSchemePrefixRe, ''); 1529} 1530/** 1531 * Strips the 'www' prefix from the given `url`. 1532 * 1533 * @private 1534 * @param {String} url The text of the anchor that is being generated, for 1535 * which to strip off the 'www' if it exists. 1536 * @return {String} The `url`, with the 'www' stripped. 1537 */ 1538function stripWwwPrefix(url) { 1539 // If the URL doesn't actually include 'www.' in it, skip running the 1540 // .replace() regexp on it, which is fairly slow even just to check the 1541 // string for the 'www.'s existence. Most URLs these days do not have 'www.' 1542 // in it, so most of the time we skip running the .replace(). One other 1543 // option in the future is to run a state machine on the `url` string 1544 if (!url.includes('www.')) { 1545 return url; 1546 } 1547 else { 1548 return url.replace(wwwPrefixRegex, '$1'); // leave any scheme ($1), it one exists 1549 } 1550} 1551/**
1552 * Strips any protocol-relative '//' from the anchor text. 1553 * 1554 * @private 1555 * @param {String} text The text of the anchor that is being generated, for which to strip off the 1556 * protocol-relative prefix (such as stripping off "//") 1557 * @return {String} The `anchorText`, with the protocol-relative prefix stripped. 1558 */ 1559function stripProtocolRelativePrefix(text) { 1560 return text.replace(protocolRelativeRegex, ''); 1561} 1562/** 1563 * Removes any trailing slash from the given `anchorText`, in preparation for the text to be displayed. 1564 * 1565 * @private 1566 * @param {String} anchorText The text of the anchor that is being generated, for which to remove any trailing 1567 * slash ('/') that may exist. 1568 * @return {String} The `anchorText`, with the trailing slash removed. 1569 */ 1570function removeTrailingSlash(anchorText) { 1571 if (anchorText.charAt(anchorText.length - 1) === '/') { 1572 anchorText = anchorText.slice(0, -1); 1573 } 1574 return anchorText; 1575} 1576/** 1577 * Decodes percent-encoded characters from the given `anchorText`, in 1578 * preparation for the text to be displayed. 1579 * 1580 * @private 1581 * @param {String} anchorText The text of the anchor that is being 1582 * generated, for which to decode any percent-encoded characters. 1583 * @return {String} The `anchorText`, with the percent-encoded characters 1584 * decoded. 1585 */ 1586function removePercentEncoding(anchorText) { 1587 // First, convert a few of the known % encodings to the corresponding 1588 // HTML entities that could accidentally be interpretted as special 1589 // HTML characters 1590 // NOTE: This used to be written as 5 separate .replace() calls, but that 1591 // was 25% slower than the current form below according to jsperf 1592 var preProcessedEntityAnchorText = anchorText.replace(/%(?:22|26|27|3C|3E)/gi, function (match) { 1593 if (match === '%22') 1594 return '"'; // %22: '"' char 1595 if (match === '%26') 1596 return '&'; // %26: '&' char 1597 if (match === '%27') 1598 return '''; // %27: "'" char 1599 if (match === '%3C' || match === '%3c') 1600 return '<'; // %3C: '<' char 1601 /*if (match === '%3E' || match === '%3e')*/ return '>'; // %3E: '>' char 1602 }); 1603 // Now attempt to URL-decode the rest of the anchor text. However, 1604 // decodeURIComponent() is a slow function. Only call it if we have 1605 // remaining %-encoded entities. Adding this check added ~300 ops/sec to 1606 // benchmark 1607 if (preProcessedEntityAnchorText.includes('%')) { 1608 try { 1609 return decodeURIComponent(preProcessedEntityAnchorText); 1610 // eslint-disable-next-line @typescript-eslint/no-unused-vars 1611 } 1612 catch (error) { 1613 // Invalid % escape sequence in the anchor text, we'll simply return 1614 // the preProcessedEntityAnchorText below 1615 } 1616 } 1617 return preProcessedEntityAnchorText; 1618} 1619 1620/** 1621 * A regular expression to match a 'mailto:' prefix on an email address. 1622 */ 1623var mailtoSchemePrefixRe = /^mailto:/i; 1624/** 1625 * Determines if the given character may start the "local part" of an email 1626 * address. The local part is the part to the left of the '@' sign. 1627 * 1628 * Technically according to the email spec, any of the characters in the 1629 * {@link emailLocalPartCharRegex} can start an email address (including any of 1630 * the special characters), but this is so rare in the wild and the 1631 * implementation is much simpler by only starting an email address with a word 1632 * character. This is especially important when matching the '{' character which 1633 * generally starts a brace that isn't part of the email address. 1634 */ 1635var isEmailLocalPartStartChar = isAlphaNumericOrMarkChar; // alias for clarity 1636/** 1637 * Determines if the given character can be part of the "local part" of an email 1638 * address. The local part is the part to the left of the '@' sign. 1639 * 1640 * Checking for an email address's start char is handled with {@link #isEmailLocalPartStartChar} 1641 */ 1642function isEmailLocalPartChar(charCode) { 1643 return isEmailLocalPartStartChar(charCode) || isValidEmailLocalPartSpecialChar(charCode); 1644} 1645/** 1646 * Determines if the given email address is valid. We consider it valid if it 1647 * has a valid TLD in its host. 1648 * 1649 * @param emailAddress email address 1650 * @return true is email have valid TLD, false otherwise 1651 */ 1652function isValidEmail(emailAddress) { 1653 var emailAddressTld = emailAddress.split('.').pop(); // as long as we have a valid string (as opposed to null or undefined), we will always get at least one element in the .split('.') array 1654 return isKnownTld(emailAddressTld); 1655} 1656 1657/** 1658 * @class Autolinker.match.Email 1659 * @extends Autolinker.match.AbstractMatch 1660 * 1661 * Represents a Email match found in an input string which should be Autolinked. 1662 * 1663 * See this class's superclass ({@link Autolinker.match.Match}) for more details. 1664 */ 1665var EmailMatch = /** @class */ (function (_super) { 1666 __extends(EmailMatch, _super); 1667 /** 1668 * @method constructor 1669 * @param {Object} cfg The configuration properties for the Match 1670 * instance, specified in an Object (map). 1671 */ 1672 function EmailMatch(cfg) { 1673 var _this = _super.call(this, cfg) || this; 1674 /** 1675 * @public 1676 * @property {'email'} type 1677 * 1678 * A string name for the type of match that this class represents. Can be 1679 * used in a TypeScript discriminating union to type-narrow from the 1680 * `Match` type. 1681 */ 1682 _this.type = 'email'; 1683 /** 1684 * @cfg {String} email (required) 1685 * 1686 * The email address that was matched. 1687 */ 1688 _this.email = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 1689 _this.email = cfg.email; 1690 return _this; 1691 } 1692 /** 1693 * Returns a string name for the type of match that this class represents. 1694 * For the case of EmailMatch, returns 'email'. 1695 * 1696 * @return {String} 1697 */ 1698 EmailMatch.prototype.getType = function () { 1699 return 'email'; 1700 }; 1701 /** 1702 * Returns the email address that was matched. 1703 * 1704 * @return {String} 1705 */ 1706 EmailMatch.prototype.getEmail = function () { 1707 return this.email; 1708 }; 1709 /**
1710 * Returns the anchor href that should be generated for the match. 1711 * 1712 * @return {String} 1713 */ 1714 EmailMatch.prototype.getAnchorHref = function () { 1715 return 'mailto:' + this.email; 1716 }; 1717 /** 1718 * Returns the anchor text that should be generated for the match. 1719 * 1720 * @return {String} 1721 */ 1722 EmailMatch.prototype.getAnchorText = function () { 1723 return this.email; 1724 }; 1725 return EmailMatch; 1726}(AbstractMatch)); 1727 1728/** 1729 * Determines if the given `char` is a an allowed character in a hashtag. These 1730 * are underscores or any alphanumeric char. 1731 */ 1732function isHashtagTextChar(charCode) { 1733 return charCode === 95 /* Char.Underscore */ || isAlphaNumericOrMarkChar(charCode); 1734} 1735/** 1736 * Determines if a hashtag match is valid. 1737 */ 1738function isValidHashtag(hashtag) { 1739 // Max length of 140 for a hashtag ('#' char + 139 word chars) 1740 return hashtag.length <= 140; 1741} 1742var hashtagServices = [ 1743 'twitter', 1744 'facebook', 1745 'instagram', 1746 'tiktok', 1747 'youtube', 1748]; 1749 1750/** 1751 * @class Autolinker.match.Hashtag 1752 * @extends Autolinker.match.AbstractMatch 1753 * 1754 * Represents a Hashtag match found in an input string which should be 1755 * Autolinked. 1756 * 1757 * See this class's superclass ({@link Autolinker.match.Match}) for more 1758 * details. 1759 */ 1760var HashtagMatch = /** @class */ (function (_super) { 1761 __extends(HashtagMatch, _super); 1762 /** 1763 * @method constructor 1764 * @param {Object} cfg The configuration properties for the Match 1765 * instance, specified in an Object (map). 1766 */ 1767 function HashtagMatch(cfg) { 1768 var _this = _super.call(this, cfg) || this; 1769 /** 1770 * @public 1771 * @property {'hashtag'} type 1772 * 1773 * A string name for the type of match that this class represents. Can be 1774 * used in a TypeScript discriminating union to type-narrow from the 1775 * `Match` type. 1776 */ 1777 _this.type = 'hashtag'; 1778 /** 1779 * @cfg {String} serviceName 1780 * 1781 * The service to point hashtag matches to. See {@link Autolinker#hashtag} 1782 * for available values. 1783 */ 1784 _this.serviceName = 'twitter'; // default value just to get the above doc comment in the ES5 output and documentation generator 1785 /** 1786 * @cfg {String} hashtag (required) 1787 * 1788 * The HashtagMatch that was matched, without the '#'. 1789 */ 1790 _this.hashtag = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 1791 _this.serviceName = cfg.serviceName; 1792 _this.hashtag = cfg.hashtag; 1793 return _this; 1794 } 1795 /** 1796 * Returns a string name for the type of match that this class represents. 1797 * For the case of HashtagMatch, returns 'hashtag'. 1798 * 1799 * @return {String} 1800 */ 1801 HashtagMatch.prototype.getType = function () { 1802 return 'hashtag'; 1803 }; 1804 /** 1805 * Returns the configured {@link #serviceName} to point the HashtagMatch to. 1806 * Ex: 'facebook', 'twitter'. 1807 * 1808 * @return {String} 1809 */ 1810 HashtagMatch.prototype.getServiceName = function () { 1811 return this.serviceName; 1812 }; 1813 /** 1814 * Returns the matched hashtag, without the '#' character. 1815 * 1816 * @return {String} 1817 */ 1818 HashtagMatch.prototype.getHashtag = function () { 1819 return this.hashtag; 1820 }; 1821 /** 1822 * Returns the anchor href that should be generated for the match. 1823 * 1824 * @return {String} 1825 */ 1826 HashtagMatch.prototype.getAnchorHref = function () { 1827 var serviceName = this.serviceName, hashtag = this.hashtag; 1828 switch (serviceName) { 1829 case 'twitter': 1830 return 'https://twitter.com/hashtag/' + hashtag; 1831 case 'facebook': 1832 return 'https://www.facebook.com/hashtag/' + hashtag; 1833 case 'instagram': 1834 return 'https://instagram.com/explore/tags/' + hashtag; 1835 case 'tiktok': 1836 return 'https://www.tiktok.com/tag/' + hashtag; 1837 case 'youtube': 1838 return 'https://youtube.com/hashtag/' + hashtag; 1839 /* istanbul ignore next */ 1840 default: 1841 // Should never happen because Autolinker's constructor should block any invali
vendor: 11,747 bytes, lines 1841-2164
1841d values, but just in case 1842 assertNever(serviceName); 1843 } 1844 }; 1845 /** 1846 * Returns the anchor text that should be generated for the match. 1847 * 1848 * @return {String} 1849 */ 1850 HashtagMatch.prototype.getAnchorText = function () { 1851 return '#' + this.hashtag; 1852 }; 1853 /** 1854 * Returns the CSS class suffixes that should be used on a tag built with 1855 * the match. See {@link Autolinker.match.Match#getCssClassSuffixes} for 1856 * details. 1857 * 1858 * @return {String[]} 1859 */ 1860 HashtagMatch.prototype.getCssClassSuffixes = function () { 1861 var cssClassSuffixes = _super.prototype.getCssClassSuffixes.call(this), serviceName = this.getServiceName(); 1862 if (serviceName) { 1863 cssClassSuffixes.push(serviceName); 1864 } 1865 return cssClassSuffixes; 1866 }; 1867 return HashtagMatch; 1868}(AbstractMatch)); 1869 1870var mentionRegexes = { 1871 twitter: /^@\w{1,15}$/, 1872 instagram: /^@[_\w]{1,30}$/, 1873 soundcloud: /^@[-a-z0-9_]{3,25}$/, 1874 // TikTok usernames are 1-24 characters containing letters, numbers, underscores 1875 // and periods, but cannot end in a period: https://support.tiktok.com/en/getting-started/setting-up-your-profile/changing-your-username 1876 tiktok: /^@[.\w]{1,23}[\w]$/, 1877 // Youtube usernames are 3-30 characters containing letters, numbers, underscores, 1878 // dashes, or latin middle dots ('·'). 1879 // https://support.google.com/youtube/answer/11585688?hl=en&co=GENIE.Platform%3DAndroid#tns 1880 youtube: /^@[-.·\w]{3,30}$/, 1881}; 1882/** 1883 * Determines if the given character can be part of a mention's text characters. 1884 * 1885 * Accepts characters that match the RegExp `/[-\w.]/`, which are the possible 1886 * mention characters for any service. 1887 * 1888 * We'll confirm the match based on the user-configured service name after the 1889 * match is found. 1890 */ 1891function isMentionTextChar(charCode) { 1892 return (charCode === 45 /* Char.Dash */ || // '-' 1893 charCode === 46 /* Char.Dot */ || // '.' 1894 charCode === 95 /* Char.Underscore */ || // '_' 1895 isAsciiLetterChar(charCode) || 1896 isDigitChar(charCode)); 1897} 1898/** 1899 * Determines if the given `mention` text is valid. 1900 */ 1901function isValidMention(mention, serviceName) { 1902 var re = mentionRegexes[serviceName]; 1903 return re.test(mention); 1904} 1905var mentionServices = [ 1906 'twitter', 1907 'instagram', 1908 'soundcloud', 1909 'tiktok', 1910 'youtube', 1911]; 1912 1913/** 1914 * @class Autolinker.match.Mention 1915 * @extends Autolinker.match.AbstractMatch 1916 * 1917 * Represents a Mention match found in an input string which should be Autolinked. 1918 * 1919 * See this class's superclass ({@link Autolinker.match.Match}) for more details. 1920 */ 1921var MentionMatch = /** @class */ (function (_super) { 1922 __extends(MentionMatch, _super); 1923 /** 1924 * @method constructor 1925 * @param {Object} cfg The configuration properties for the Match 1926 * instance, specified in an Object (map). 1927 */ 1928 function MentionMatch(cfg) { 1929 var _this = _super.call(this, cfg) || this; 1930 /** 1931 * @public 1932 * @property {'mention'} type 1933 * 1934 * A string name for the type of match that this class represents. Can be 1935 * used in a TypeScript discriminating union to type-narrow from the 1936 * `Match` type. 1937 */ 1938 _this.type = 'mention'; 1939 /** 1940 * @cfg {String} serviceName 1941 * 1942 * The service to point mention matches to. See {@link Autolinker#mention} 1943 * for available values. 1944 */ 1945 _this.serviceName = 'twitter'; // default value just to get the above doc comment in the ES5 output and documentation generator 1946 /** 1947 * @cfg {String} mention (required) 1948 * 1949 * The Mention that was matched, without the '@' character. 1950 */ 1951 _this.mention = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 1952 _this.mention = cfg.mention; 1953 _this.serviceName = cfg.serviceName; 1954 return _this; 1955 } 1956 /** 1957 * Returns a string name for the type of match that this class represents. 1958 * For the case of MentionMatch, returns 'mention'. 1959 * 1960 * @return {String} 1961 */ 1962 MentionMatch.prototype.getType = function () { 1963 return 'mention'; 1964 }; 1965 /** 1966 * Returns the mention, without the '@' character. 1967 * 1968 * @return {String} 1969 */ 1970 MentionMatch.prototype.getMention = function () { 1971 return this.mention; 1972 }; 1973 /** 1974 * Returns the configured {@link #serviceName} to point the mention to. 1975 * Ex: 'instagram', 'twitter', 'soundcloud'. 1976 * 1977 * @return {String} 1978 */ 1979 MentionMatch.prototype.getServiceName = function () { 1980 return this.serviceName; 1981 }; 1982 /** 1983 * Returns the anchor href that should be generated for the match. 1984 * 1985 * @return {String} 1986 */ 1987 MentionMatch.prototype.getAnchorHref = function () { 1988 switch (this.serviceName) { 1989 case 'twitter': 1990 return 'https://twitter.com/' + this.mention; 1991 case 'instagram': 1992 return 'https://instagram.com/' + this.mention; 1993 case 'soundcloud': 1994 return 'https://soundcloud.com/' + this.mention; 1995 case 'tiktok': 1996 return 'https://www.tiktok.com/@' + this.mention; 1997 case 'youtube': 1998 return 'https://youtube.com/@' + this.mention; 1999 /* istanbul ignore next */ 2000 default: 2001 // Should never happen because Autolinker's constructor should block any invalid values, but just in case. 2002 assertNever(this.serviceName); 2003 } 2004 }; 2005 /** 2006 * Returns the anchor text that should be generated for the match. 2007 * 2008 * @return {String} 2009 */ 2010 MentionMatch.prototype.getAnchorText = function () { 2011 return '@' + this.mention; 2012 }; 2013 /** 2014 * Returns the CSS class suffixes that should be used on a tag built with 2015 * the match. See {@link Autolinker.match.Match#getCssClassSuffixes} for 2016 * details. 2017 * 2018 * @return {String[]} 2019 */ 2020 MentionMatch.prototype.getCssClassSuffixes = function () { 2021 var cssClassSuffixes = _super.prototype.getCssClassSuffixes.call(this), serviceName = this.getServiceName(); 2022 if (serviceName) { 2023 cssClassSuffixes.push(serviceName); 2024 } 2025 return cssClassSuffixes; 2026 }; 2027 return MentionMatch; 2028}(AbstractMatch)); 2029 2030// Regex that specifies any delimiter char that allows us to treat the number as 2031// a phone number rather than just any other number that could appear in text. 2032var hasDelimCharsRe = /[-. ()]/; 2033// Over the years, many people have added to this regex, but it should have been 2034// split up by country. Maybe one day we can break this down. 2035var mostPhoneNumbers = /(?:(?:(?:(\+)?\d{1,3}[-. ]?)?\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4})|(?:(\+)(?:9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)[-. ]?(?:\d[-. ]?){6,12}\d+))([,;]+[0-9]+#?)*/; 2036// Regex for Japanese phone numbers 2037var japanesePhoneRe = /(0([1-9]-?[1-9]\d{3}|[1-9]{2}-?\d{3}|[1-9]{2}\d{1}-?\d{2}|[1-9]{2}\d{2}-?\d{1})-?\d{4}|0[789]0-?\d{4}-?\d{4}|050-?\d{4}-?\d{4})/; 2038// Combined regex 2039var validPhoneNumberRe = new RegExp("^".concat(mostPhoneNumbers.source, "|").concat(japanesePhoneRe.source, "$")); 2040/** 2041 * Determines if the character is a phone number separator character (i.e. 2042 * '-', '.', or ' ' (space)) 2043 */ 2044function isPhoneNumberSeparatorChar(charCode) { 2045 return (charCode === 45 /* Char.Dash */ || // '-' 2046 charCode === 46 /* Char.Dot */ || // '.' 2047 charCode === 32 /* Char.Space */ // ' ' 2048 ); 2049} 2050/** 2051 * Determines if the character is a control character in a phone number. Control 2052 * characters are as follows: 2053 * 2054 * - ',': A 1 second pause. Useful for dialing extensions once the main phone number has been reached 2055 * - ';': A "wait" that waits for the user to take action (tap something, for instance on a smart phone) 2056 */ 2057function isPhoneNumberControlChar(charCode) { 2058 return (charCode === 44 /* Char.Comma */ || // ',' 2059 charCode === 59 /* Char.SemiColon */ // ';' 2060 ); 2061} 2062/** 2063 * Determines if the given phone number text found in a string is a valid phone 2064 * number. 2065 * 2066 * Our state machine parser is simplified to grab anything that looks like a 2067 * phone number, and this function confirms the match. 2068 */ 2069function isValidPhoneNumber(phoneNumberText) { 2070 // We'll only consider the match as a phone number if there is some kind of 2071 // delimiter character (a prefixed '+' sign, or separator chars). 2072 // 2073 // Accepts: 2074 // (123) 456-7890 2075 // +38755233976 2076 // Does not accept: 2077 // 1234567890 (no delimiter chars - may just be a random number that's not a phone number) 2078 var hasDelimiters = phoneNumberText.charAt(0) === '+' || hasDelimCharsRe.test(phoneNumberText); 2079 return hasDelimiters && validPhoneNumberRe.test(phoneNumberText); 2080} 2081 2082/** 2083 * @class Autolinker.match.Phone 2084 * @extends Autolinker.match.AbstractMatch 2085 * 2086 * Represents a Phone number match found in an input string which should be 2087 * Autolinked. 2088 * 2089 * See this class's superclass ({@link Autolinker.match.Match}) for more 2090 * details. 2091 */ 2092var PhoneMatch = /** @class */ (function (_super) { 2093 __extends(PhoneMatch, _super); 2094 /** 2095 * @method constructor 2096 * @param {Object} cfg The configuration properties for the Match 2097 * instance, specified in an Object (map). 2098 */ 2099 function PhoneMatch(cfg) { 2100 var _this = _super.call(this, cfg) || this; 2101 /** 2102 * @public 2103 * @property {'phone'} type 2104 * 2105 * A string name for the type of match that this class represents. Can be 2106 * used in a TypeScript discriminating union to type-narrow from the 2107 * `Match` type. 2108 */ 2109 _this.type = 'phone'; 2110 /** 2111 * @protected 2112 * @property {String} number (required) 2113 * 2114 * The phone number that was matched, without any delimiter characters. 2115 * 2116 * Note: This is a string to allow for prefixed 0's. 2117 */ 2118 _this.number = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 2119 /** 2120 * @protected 2121 * @property {Boolean} plusSign (required) 2122 * 2123 * `true` if the matched phone number started with a '+' sign. We'll include 2124 * it in the `tel:` URL if so, as this is needed for international numbers. 2125 * 2126 * Ex: '+1 (123) 456 7879' 2127 */ 2128 _this.plusSign = false; // default value just to get the above doc comment in the ES5 output and documentation generator 2129 _this.number = cfg.number; 2130 _this.plusSign = cfg.plusSign; 2131 return _this; 2132 } 2133 /** 2134 * Returns a string name for the type of match that this class represents. 2135 * For the case of PhoneMatch, returns 'phone'. 2136 * 2137 * @return {String} 2138 */ 2139 PhoneMatch.prototype.getType = function () { 2140 return 'phone'; 2141 }; 2142 /** 2143 * Returns the phone number that was matched as a string, without any 2144 * delimiter characters. 2145 * 2146 * Note: This is a string to allow for prefixed 0's. 2147 * 2148 * @return {String} 2149 */ 2150 PhoneMatch.prototype.getPhoneNumber = function () { 2151 return this.number; 2152 }; 2153 /** 2154 * Alias of {@link #getPhoneNumber}, returns the phone number that was 2155 * matched as a string, without any delimiter characters. 2156 * 2157 * Note: This is a string to allow for prefixed 0's. 2158 * 2159 * @return {String} 2160 */ 2161 PhoneMatch.prototype.getNumber = function () { 2162 return this.getPhoneNumber(); 2163 }; 2164 /**
2165 * Returns the anchor href that should be generated for the match. 2166 * 2167 * @return {String} 2168 */ 2169 PhoneMatch.prototype.getAnchorHref = function () { 2170 return 'tel:' + (this.plusSign ? '+' : '') + this.number; 2171 }; 2172 /** 2173 * Returns the anchor text that should be generated for the match. 2174 * 2175 * @return {String} 2176 */ 2177 PhoneMatch.prototype.getAnchorText = function () { 2178 return this.matchedText; 2179 }; 2180 return PhoneMatch; 2181}(AbstractMatch));
vendor: 7,811 bytes, lines 2182-2332
2182 2183// For debugging: search for and uncomment other "For debugging" lines 2184// import CliTable from 'cli-table'; 2185/** 2186 * Context object containing all the state needed by the state machine functions. 2187 * 2188 * ## Historical note 2189 * 2190 * In v4.1.1, we used nested functions to handle the context via closures, but 2191 * this necessitated re-creating the functions for each call to `parseMatches()`, 2192 * which made them difficult for v8 to JIT optimize. In v4.1.2, we lifted all of 2193 * the functions to the top-level scope and passed the context object between 2194 * them, which allows the functions to be JIT compiled once and reused. 2195 */ 2196var ParseMatchesContext = /** @class */ (function () { 2197 function ParseMatchesContext(text, args) { 2198 this.charIdx = 0; // Current character index being processed 2199 this.matches = []; // Collection of matches found 2200 this._stateMachines = []; // Array of active state machines 2201 this.schemeUrlMachinesCount = 0; // part of an optimization to remove the need to go into a slow code block when unnecessary. Since it's been so long since the initial implementation, not sure that this can ever go above 1, but keeping it as a counter to be safe 2202 this.text = text; 2203 this.tagBuilder = args.tagBuilder; 2204 this.stripPrefix = args.stripPrefix; 2205 this.stripTrailingSlash = args.stripTrailingSlash; 2206 this.decodePercentEncoding = args.decodePercentEncoding; 2207 this.hashtagServiceName = args.hashtagServiceName; 2208 this.mentionServiceName = args.mentionServiceName; 2209 } 2210 Object.defineProperty(ParseMatchesContext.prototype, "stateMachines", { 2211 get: function () { 2212 return this._stateMachines; 2213 }, 2214 enumerable: false, 2215 configurable: true 2216 }); 2217 ParseMatchesContext.prototype.addMachine = function (stateMachine) { 2218 this._stateMachines.push(stateMachine); 2219 if (isSchemeUrlStateMachine(stateMachine)) { 2220 this.schemeUrlMachinesCount++; 2221 } 2222 }; 2223 ParseMatchesContext.prototype.removeMachine = function (stateMachine) { 2224 // Performance note: this was originally implemented with Array.prototype.splice() 2225 // and mutated the array in place. Switching to filter added ~280ops/sec 2226 // on the benchmark, although likely at the expense of GC time. Perhaps 2227 // in the future, we implement a rotating array so we never need to move 2228 // or clean anything up 2229 this._stateMachines = this._stateMachines.filter(function (m) { return m !== stateMachine; }); 2230 // If we've removed the URL state machine, set the flag to false. 2231 // This flag is a quick test that helps us skip a slow section of 2232 // code when there is already a URL state machine present. 2233 if (isSchemeUrlStateMachine(stateMachine)) { 2234 this.schemeUrlMachinesCount--; 2235 } 2236 }; 2237 ParseMatchesContext.prototype.hasSchemeUrlMachine = function () { 2238 return this.schemeUrlMachinesCount > 0; 2239 }; 2240 return ParseMatchesContext; 2241}()); 2242/** 2243 * Parses URL, email, twitter, mention, and hashtag matches from the given 2244 * `text`. 2245 */ 2246function parseMatches(text, args) { 2247 // Create the context object that will be passed to all state functions 2248 var context = new ParseMatchesContext(text, args); 2249 // For debugging: search for and uncomment other "For debugging" lines 2250 // const table = new CliTable({ 2251 // head: ['charIdx', 'char', 'code', 'type', 'states', 'startIdx', 'reached accept state'], 2252 // }); 2253 for (; context.charIdx < context.text.length; context.charIdx++) { 2254 var char = text.charAt(context.charIdx); 2255 var charCode = text.charCodeAt(context.charIdx); 2256 if (context.stateMachines.length === 0) { 2257 stateNoMatch(context, char, charCode); 2258 } 2259 else { 2260 // Must loop through the state machines backwards for when one 2261 // is removed 2262 for (var stateIdx = context.stateMachines.length - 1; stateIdx >= 0; stateIdx--) { 2263 var stateMachine = context.stateMachines[stateIdx]; 2264 switch (stateMachine.state) { 2265 // Protocol-relative URL states 2266 case 11 /* State.ProtocolRelativeSlash1 */: 2267 stateProtocolRelativeSlash1(context, stateMachine, charCode); 2268 break; 2269 case 12 /* State.ProtocolRelativeSlash2 */: 2270 stateProtocolRelativeSlash2(context, stateMachine, charCode); 2271 break; 2272 case 0 /* State.SchemeChar */: 2273 stateSchemeChar(context, stateMachine, charCode); 2274 break; 2275 case 1 /* State.SchemeHyphen */: 2276 stateSchemeHyphen(context, stateMachine, charCode); 2277 break; 2278 case 2 /* State.SchemeColon */: 2279 stateSchemeColon(context, stateMachine, charCode); 2280 break; 2281 case 3 /* State.SchemeSlash1 */: 2282 stateSchemeSlash1(context, stateMachine, charCode); 2283 break; 2284 case 4 /* State.SchemeSlash2 */: 2285 stateSchemeSlash2(context, stateMachine, char, charCode); 2286 break; 2287 case 5 /* State.DomainLabelChar */: 2288 stateDomainLabelChar(context, stateMachine, charCode); 2289 break; 2290 case 6 /* State.DomainHyphen */: 2291 stateDomainHyphen(context, stateMachine, char, charCode); 2292 break; 2293 case 7 /* State.DomainDot */: 2294 stateDomainDot(context, stateMachine, char, charCode); 2295 break; 2296 case 13 /* State.IpV4Digit */: 2297 stateIpV4Digit(context, stateMachine, charCode); 2298 break; 2299 case 14 /* State.IpV4Dot */: 2300 stateIpV4Dot(context, stateMachine, charCode); 2301 break; 2302 case 8 /* State.PortColon */: 2303 statePortColon(context, stateMachine, charCode); 2304 break; 2305 case 9 /* State.PortNumber */: 2306 statePortNumber(context, stateMachine, charCode); 2307 break; 2308 case 10 /* State.Path */: 2309 statePath(context, stateMachine, charCode); 2310 break; 2311 // Email States 2312 case 15 /* State.EmailMailto_M */: 2313 stateEmailMailto_M(context, stateMachine, char, charCode); 2314 break; 2315 case 16 /* State.EmailMailto_A */: 2316 stateEmailMailto_A(context, stateMachine, char, charCode); 2317 break; 2318 case 17 /* State.EmailMailto_I */: 2319 stateEmailMailto_I(context, stateMachine, char, charCode); 2320 break; 2321 case 18 /* State.EmailMailto_L */: 2322 stateEmailMailto_L(context, stateMachine, char, charCode); 2323 break; 2324 case 19 /* State.EmailMailto_T */: 2325 stateEmailMailto_T(context, stateMachine, char, charCode); 2326 break; 2327 case 20 /* State.EmailMailto_O */: 2328 stateEmailMailto_O(context, stateMachine, charCode); 2329 break; 2330 case 21 /* State.EmailMailto_Colon */: 2331 stateEmailMailtoColon(context, stateMachine, charCode); 2332 break;
vendor: 9,630 bytes, lines 2333-2510
2333 case 22 /* State.EmailLocalPart */: 2334 stateEmailLocalPart(context, stateMachine, charCode); 2335 break; 2336 case 23 /* State.EmailLocalPartDot */: 2337 stateEmailLocalPartDot(context, stateMachine, charCode); 2338 break; 2339 case 24 /* State.EmailAtSign */: 2340 stateEmailAtSign(context, stateMachine, charCode); 2341 break; 2342 case 25 /* State.EmailDomainChar */: 2343 stateEmailDomainChar(context, stateMachine, charCode); 2344 break; 2345 case 26 /* State.EmailDomainHyphen */: 2346 stateEmailDomainHyphen(context, stateMachine, charCode); 2347 break; 2348 case 27 /* State.EmailDomainDot */: 2349 stateEmailDomainDot(context, stateMachine, charCode); 2350 break; 2351 // Hashtag states 2352 case 28 /* State.HashtagHashChar */: 2353 stateHashtagHashChar(context, stateMachine, charCode); 2354 break; 2355 case 29 /* State.HashtagTextChar */: 2356 stateHashtagTextChar(context, stateMachine, charCode); 2357 break; 2358 // Mention states 2359 case 30 /* State.MentionAtChar */: 2360 stateMentionAtChar(context, stateMachine, charCode); 2361 break; 2362 case 31 /* State.MentionTextChar */: 2363 stateMentionTextChar(context, stateMachine, charCode); 2364 break; 2365 // Phone number states 2366 case 32 /* State.PhoneNumberOpenParen */: 2367 statePhoneNumberOpenParen(context, stateMachine, char, charCode); 2368 break; 2369 case 33 /* State.PhoneNumberAreaCodeDigit1 */: 2370 statePhoneNumberAreaCodeDigit1(context, stateMachine, charCode); 2371 break; 2372 case 34 /* State.PhoneNumberAreaCodeDigit2 */: 2373 statePhoneNumberAreaCodeDigit2(context, stateMachine, charCode); 2374 break; 2375 case 35 /* State.PhoneNumberAreaCodeDigit3 */: 2376 statePhoneNumberAreaCodeDigit3(context, stateMachine, charCode); 2377 break; 2378 case 36 /* State.PhoneNumberCloseParen */: 2379 statePhoneNumberCloseParen(context, stateMachine, char, charCode); 2380 break; 2381 case 37 /* State.PhoneNumberPlus */: 2382 statePhoneNumberPlus(context, stateMachine, char, charCode); 2383 break; 2384 case 38 /* State.PhoneNumberDigit */: 2385 statePhoneNumberDigit(context, stateMachine, char, charCode); 2386 break; 2387 case 39 /* State.PhoneNumberSeparator */: 2388 statePhoneNumberSeparator(context, stateMachine, char, charCode); 2389 break; 2390 case 40 /* State.PhoneNumberControlChar */: 2391 statePhoneNumberControlChar(context, stateMachine, charCode); 2392 break; 2393 case 41 /* State.PhoneNumberPoundChar */: 2394 statePhoneNumberPoundChar(context, stateMachine, charCode); 2395 break; 2396 /* istanbul ignore next */ 2397 default: 2398 assertNever(stateMachine.state); 2399 } 2400 } 2401 // Special case for handling a colon (or other non-alphanumeric) 2402 // when preceded by another character, such as in the text: 2403 // Link 1:http://google.com 2404 // In this case, the 'h' character after the colon wouldn't start a 2405 // new scheme url because we'd be in a ipv4 or tld url and the colon 2406 // would be interpreted as a port ':' char. Also, only start a new 2407 // scheme url machine if there isn't currently one so we don't start 2408 // new ones for colons inside a url 2409 // 2410 // TODO: The addition of this snippet (to fix the bug) in 4.0.1 lost 2411 // us ~500 ops/sec on the benchmarks. Optimizing it with the 2412 // hasSchemeUrlMachine() flag and optimizing the isSchemeStartChar() 2413 // method for 4.1.3 got us back about ~400ops/sec. One potential way 2414 // to improve this even ore is to add this snippet to individual 2415 // state handler functions where it can occur to prevent running it 2416 // on every loop interation. 2417 if (!context.hasSchemeUrlMachine() && 2418 context.charIdx > 0 && 2419 isSchemeStartChar(charCode)) { 2420 var prevCharCode = context.text.charCodeAt(context.charIdx - 1); 2421 if (!isSchemeStartChar(prevCharCode)) { 2422 context.addMachine(createSchemeUrlStateMachine(context.charIdx, 0 /* State.SchemeChar */)); 2423 } 2424 } 2425 } 2426 // For debugging: search for and uncomment other "For debugging" lines 2427 // table.push([ 2428 // String(context.charIdx), 2429 // char, 2430 // `10: ${char.charCodeAt(0)}\n0x: ${char.charCodeAt(0).toString(16)}\nU+${char.codePointAt(0)}`, 2431 // context.stateMachines.map(machine => `${StateMachineType[machine.type]}${'matchType' in machine ? ` (${UrlStateMachineMatchType[machine.matchType]})` : ''}`).join('\n') || '(none)', 2432 // context.stateMachines.map(machine => State[machine.state]).join('\n') || '(none)', 2433 // context.stateMachines.map(m => m.startIdx).join('\n'), 2434 // context.stateMachines.map(m => m.acceptStateReached).join('\n'), 2435 // ]); 2436 } 2437 // Capture any valid match at the end of the string 2438 // Note: this loop must happen in reverse because 2439 // captureMatchIfValidAndRemove() removes state machines from the array 2440 // and we'll end up skipping every other one if we remove while looping 2441 // forward 2442 for (var i = context.stateMachines.length - 1; i >= 0; i--) { 2443 context.stateMachines.forEach(function (stateMachine) { 2444 return captureMatchIfValidAndRemove(context, stateMachine); 2445 }); 2446 } 2447 // For debugging: search for and uncomment other "For debugging" lines 2448 // console.log(`\nRead string:\n ${text}`); 2449 // console.log(table.toString()); 2450 return context.matches; 2451} 2452/** 2453 * Handles the state when we're not in a URL/email/etc. (i.e. when no state machines exist) 2454 */ 2455function stateNoMatch(context, char, charCode) { 2456 var charIdx = context.charIdx; 2457 if (charCode === 35 /* Char.NumberSign */ /* '#' */) { 2458 // Hash char, start a Hashtag match 2459 context.addMachine(createHashtagStateMachine(charIdx, 28 /* State.HashtagHashChar */)); 2460 } 2461 else if (charCode === 64 /* Char.AtSign */ /* '@' */) { 2462 // '@' char, start a Mention match 2463 context.addMachine(createMentionStateMachine(charIdx, 30 /* State.MentionAtChar */)); 2464 } 2465 else if (charCode === 47 /* Char.Slash */ /* '/' */) { 2466 // A slash could begin a protocol-relative URL 2467 context.addMachine(createTldUrlStateMachine(charIdx, 11 /* State.ProtocolRelativeSlash1 */)); 2468 } 2469 else if (charCode === 43 /* Char.Plus */ /* '+' */) { 2470 // A '+' char can start a Phone number 2471 context.addMachine(createPhoneNumberStateMachine(charIdx, 37 /* State.PhoneNumberPlus */)); 2472 } 2473 else if (charCode === 40 /* Char.OpenParen */ /* '(' */) { 2474 context.addMachine(createPhoneNumberStateMachine(charIdx, 32 /* State.PhoneNumberOpenParen */)); 2475 } 2476 else { 2477 if (isDigitChar(charCode)) { 2478 // A digit could start a phone number 2479 context.addMachine(createPhoneNumberStateMachine(charIdx, 38 /* State.PhoneNumberDigit */)); 2480 // A digit could start an IP address 2481 context.addMachine(createIpV4UrlStateMachine(charIdx, 13 /* State.IpV4Digit */)); 2482 } 2483 if (isEmailLocalPartStartChar(charCode)) { 2484 // Any email local part. An 'm' character in particular could 2485 // start a 'mailto:' match 2486 var startState = char.toLowerCase() === 'm' ? 15 /* State.EmailMailto_M */ : 22 /* State.EmailLocalPart */; 2487 context.addMachine(createEmailStateMachine(charIdx, startState)); 2488 } 2489 if (isSchemeStartChar(charCode)) { 2490 // An uppercase or lowercase letter may start a scheme match 2491 context.addMachine(createSchemeUrlStateMachine(charIdx, 0 /* State.SchemeChar */)); 2492 } 2493 if (isAlphaNumericOrMarkChar(charCode)) { 2494 // A unicode alpha character or digit could start a domain name 2495 // label for a TLD match 2496 context.addMachine(createTldUrlStateMachine(charIdx, 5 /* State.DomainLabelChar */)); 2497 } 2498 } 2499 // Anything else, remain in the "non-url" state by not creating any 2500 // state machines 2501} 2502// Implements ABNF: ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) 2503function stateSchemeChar(context, stateMachine, charCode) { 2504 if (charCode === 58 /* Char.Colon */ /* ':' */) { 2505 stateMachine.state = 2 /* State.SchemeColon */; 2506 } 2507 else if (charCode === 45 /* Char.Dash */ /* '-' */) { 2508 stateMachine.state = 1 /* State.SchemeHyphen */; 2509 } 2510 else if (isSchemeChar(charCode))
vendor: 8,995 bytes, lines 2510-2749
2510; 2511 else { 2512 // Any other character, not a scheme 2513 context.removeMachine(stateMachine); 2514 } 2515} 2516function stateSchemeHyphen(context, stateMachine, charCode) { 2517 var charIdx = context.charIdx; 2518 if (charCode === 45 /* Char.Dash */ /* '-' */) ; 2519 else if (charCode === 47 /* Char.Slash */ /* '/' */) { 2520 // Not a valid scheme match, but may be the start of a 2521 // protocol-relative match (such as //google.com) 2522 context.removeMachine(stateMachine); 2523 context.addMachine(createTldUrlStateMachine(charIdx, 11 /* State.ProtocolRelativeSlash1 */)); 2524 } 2525 else if (isSchemeChar(charCode)) { 2526 stateMachine.state = 0 /* State.SchemeChar */; 2527 } 2528 else { 2529 // Any other character, not a scheme 2530 context.removeMachine(stateMachine); 2531 } 2532} 2533// https://tools.ietf.org/html/rfc3986#appendix-A 2534function stateSchemeColon(context, stateMachine, charCode) { 2535 var charIdx = context.charIdx; 2536 if (charCode === 47 /* Char.Slash */ /* '/' */) { 2537 stateMachine.state = 3 /* State.SchemeSlash1 */; 2538 } 2539 else if (charCode === 46 /* Char.Dot */ /* '.' */) { 2540 // We've read something like 'hello:.' - don't capture 2541 context.removeMachine(stateMachine); 2542 } 2543 else if (isDomainLabelStartChar(charCode)) { 2544 stateMachine.state = 5 /* State.DomainLabelChar */; 2545 // It's possible that we read an "introduction" piece of text, 2546 // and the character after the current colon actually starts an 2547 // actual scheme. An example of this is: 2548 // "The link:http://google.com" 2549 // Hence, start a new machine to capture this match if so 2550 if (isSchemeStartChar(charCode)) { 2551 context.addMachine(createSchemeUrlStateMachine(charIdx, 0 /* State.SchemeChar */)); 2552 } 2553 } 2554 else { 2555 context.removeMachine(stateMachine); 2556 } 2557} 2558// https://tools.ietf.org/html/rfc3986#appendix-A 2559function stateSchemeSlash1(context, stateMachine, charCode) { 2560 if (charCode === 47 /* Char.Slash */ /* '/' */) { 2561 stateMachine.state = 4 /* State.SchemeSlash2 */; 2562 } 2563 else if (isPathChar(charCode)) { 2564 stateMachine.state = 10 /* State.Path */; 2565 stateMachine.acceptStateReached = true; 2566 } 2567 else { 2568 captureMatchIfValidAndRemove(context, stateMachine); 2569 } 2570} 2571function stateSchemeSlash2(context, stateMachine, char, charCode) { 2572 if (charCode === 47 /* Char.Slash */ /* '/' */) { 2573 // 3rd slash, must be an absolute path (`path-absolute` in the 2574 // ABNF), such as in "file:///c:/windows/etc". See 2575 // https://tools.ietf.org/html/rfc3986#appendix-A 2576 stateMachine.state = 10 /* State.Path */; 2577 stateMachine.acceptStateReached = true; 2578 } 2579 else if (isDomainLabelStartChar(charCode)) { 2580 // start of "authority" section - see https://tools.ietf.org/html/rfc3986#appendix-A 2581 stateMachine.state = 5 /* State.DomainLabelChar */; 2582 stateMachine.acceptStateReached = true; 2583 } 2584 else { 2585 // not valid 2586 context.removeMachine(stateMachine); 2587 } 2588} 2589// Handles after we've read a '/' from the NonUrl state 2590function stateProtocolRelativeSlash1(context, stateMachine, charCode) { 2591 if (charCode === 47 /* Char.Slash */ /* '/' */) { 2592 stateMachine.state = 12 /* State.ProtocolRelativeSlash2 */; 2593 } 2594 else { 2595 // Anything else, cannot be the start of a protocol-relative 2596 // URL. 2597 context.removeMachine(stateMachine); 2598 } 2599} 2600// Handles after we've read a second '/', which could start a protocol-relative URL 2601function stateProtocolRelativeSlash2(context, stateMachine, charCode) { 2602 if (isDomainLabelStartChar(charCode)) { 2603 stateMachine.state = 5 /* State.DomainLabelChar */; 2604 } 2605 else { 2606 // Anything else, not a URL 2607 context.removeMachine(stateMachine); 2608 } 2609} 2610// Handles when we have read a domain label character 2611function stateDomainLabelChar(context, stateMachine, charCode) { 2612 if (charCode === 46 /* Char.Dot */ /* '.' */) { 2613 stateMachine.state = 7 /* State.DomainDot */; 2614 } 2615 else if (charCode === 45 /* Char.Dash */ /* '-' */) { 2616 stateMachine.state = 6 /* State.DomainHyphen */; 2617 } 2618 else if (charCode === 58 /* Char.Colon */ /* ':' */) { 2619 // Beginning of a port number, end the domain name 2620 stateMachine.state = 8 /* State.PortColon */; 2621 } 2622 else if (isUrlSuffixStartChar(charCode)) { 2623 // '/', '?', or '#' 2624 stateMachine.state = 10 /* State.Path */; 2625 } 2626 else if (isDomainLabelChar(charCode)) ; 2627 else { 2628 // Anything else, end the domain name 2629 captureMatchIfValidAndRemove(context, stateMachine); 2630 } 2631} 2632function stateDomainHyphen(context, stateMachine, char, charCode) { 2633 if (charCode === 45 /* Char.Dash */ /* '-' */) ; 2634 else if (charCode === 46 /* Char.Dot */ /* '.' */) { 2635 // Not valid to have a '-.' in a domain label 2636 captureMatchIfValidAndRemove(context, stateMachine); 2637 } 2638 else if (isDomainLabelStartChar(charCode)) { 2639 stateMachine.state = 5 /* State.DomainLabelChar */; 2640 } 2641 else { 2642 captureMatchIfValidAndRemove(context, stateMachine); 2643 } 2644} 2645function stateDomainDot(context, stateMachine, char, charCode) { 2646 if (charCode === 46 /* Char.Dot */ /* '.' */) { 2647 // domain names cannot have multiple '.'s next to each other. 2648 // It's possible we've already read a valid domain name though, 2649 // and that the '..' sequence just forms an ellipsis at the end 2650 // of a sentence 2651 captureMatchIfValidAndRemove(context, stateMachine); 2652 } 2653 else if (isDomainLabelStartChar(charCode)) { 2654 stateMachine.state = 5 /* State.DomainLabelChar */; 2655 stateMachine.acceptStateReached = true; // after hitting a dot, and then another domain label, we've reached an accept state 2656 } 2657 else { 2658 // Anything else, end the domain name 2659 captureMatchIfValidAndRemove(context, stateMachine); 2660 } 2661} 2662function stateIpV4Digit(context, stateMachine, charCode) { 2663 if (charCode === 46 /* Char.Dot */ /* '.' */) { 2664 stateMachine.state = 14 /* State.IpV4Dot */; 2665 } 2666 else if (charCode === 58 /* Char.Colon */ /* ':' */) { 2667 // Beginning of a port number 2668 stateMachine.state = 8 /* State.PortColon */; 2669 } 2670 else if (isDigitChar(charCode)) ; 2671 else if (isUrlSuffixStartChar(charCode)) { 2672 stateMachine.state = 10 /* State.Path */; 2673 } 2674 else if (isAlphaNumericOrMarkChar(charCode)) { 2675 // If we hit an alpha character, must not be an IPv4 2676 // Example of this: 1.2.3.4abc 2677 context.removeMachine(stateMachine); 2678 } 2679 else { 2680 captureMatchIfValidAndRemove(context, stateMachine); 2681 } 2682} 2683function stateIpV4Dot(context, stateMachine, charCode) { 2684 if (isDigitChar(charCode)) { 2685 stateMachine.octetsEncountered++; 2686 // Once we have encountered 4 octets, it's *potentially* a valid 2687 // IPv4 address. Our IPv4 regex will confirm the match later 2688 // though to make sure each octet is in the 0-255 range, and 2689 // there's exactly 4 octets (not 5 or more) 2690 if (stateMachine.octetsEncountered === 4) { 2691 stateMachine.acceptStateReached = true; 2692 } 2693 stateMachine.state = 13 /* State.IpV4Digit */; 2694 } 2695 else { 2696 captureMatchIfValidAndRemove(context, stateMachine); 2697 } 2698} 2699function statePortColon(context, stateMachine, charCode) { 2700 if (isDigitChar(charCode)) { 2701 stateMachine.state = 9 /* State.PortNumber */; 2702 } 2703 else { 2704 captureMatchIfValidAndRemove(context, stateMachine); 2705 } 2706} 2707function statePortNumber(context, stateMachine, charCode) { 2708 if (isDigitChar(charCode)) ; 2709 else if (isUrlSuffixStartChar(charCode)) { 2710 // '/', '?', or '#' 2711 stateMachine.state = 10 /* State.Path */; 2712 } 2713 else { 2714 captureMatchIfValidAndRemove(context, stateMachine); 2715 } 2716} 2717function statePath(context, stateMachine, charCode) { 2718 if (isPathChar(charCode)) ; 2719 else { 2720 captureMatchIfValidAndRemove(context, stateMachine); 2721 } 2722} 2723// Handles if we're reading a 'mailto:' prefix on the string 2724function stateEmailMailto_M(context, stateMachine, char, charCode) { 2725 if (char.toLowerCase() === 'a') { 2726 stateMachine.state = 16 /* State.EmailMailto_A */; 2727 } 2728 else { 2729 stateEmailLocalPart(context, stateMachine, charCode); 2730 } 2731} 2732function stateEmailMailto_A(context, stateMachine, char, charCode) { 2733 if (char.toLowerCase() === 'i') { 2734 stateMachine.state = 17 /* State.EmailMailto_I */; 2735 } 2736 else { 2737 stateEmailLocalPart(context, stateMachine, charCode); 2738 } 2739} 2740function stateEmailMailto_I(context, stateMachine, char, charCode) { 2741 if (char.toLowerCase() === 'l') { 2742 stateMachine.state = 18 /* State.EmailMailto_L */; 2743 } 2744 else { 2745 stateEmailLocalPart(context, stateMachine, charCode); 2746 } 2747} 2748function stateEmailMailto_L(context, stateMachine, char, charCode) { 2749 if (char.toLowerCase() === 't') {
2750 stateMachine.state = 19 /* State.EmailMailto_T */; 2751 } 2752 else { 2753 stateEmailLocalPart(context, stateMachine, charCode); 2754 } 2755} 2756function stateEmailMailto_T(context, stateMachine, char, charCode) { 2757 if (char.toLowerCase() === 'o') { 2758 stateMachine.state = 20 /* State.EmailMailto_O */; 2759 } 2760 else { 2761 stateEmailLocalPart(context, stateMachine, charCode); 2762 } 2763} 2764function stateEmailMailto_O(context, stateMachine, charCode) { 2765 if (charCode === 58 /* Char.Colon */ /* ':' */) { 2766 stateMachine.state = 21 /* State.EmailMailto_Colon */; 2767 } 2768 else { 2769 stateEmailLocalPart(context, stateMachine, charCode); 2770 } 2771} 2772function stateEmailMailtoColon(context, stateMachine, charCode) { 2773 if (isEmailLocalPartChar(charCode)) { 2774 stateMachine.state = 22 /* State.EmailLocalPart */; 2775 } 2776 else { 2777 context.removeMachine(stateMachine); 2778 } 2779} 2780// Handles the state when we're currently in the "local part" of an 2781// email address (as opposed to the "domain part") 2782function stateEmailLocalPart(context, stateMachine, charCode) { 2783 if (charCode === 46 /* Char.Dot */ /* '.' */) { 2784 stateMachine.state = 23 /* State.EmailLocalPartDot */; 2785 } 2786 else if (charCode === 64 /* Char.AtSign */ /* '@' */) { 2787 stateMachine.state = 24 /* State.EmailAtSign */; 2788 } 2789 else if (isEmailLocalPartChar(charCode)) { 2790 // stay in the "local part" of the email address 2791 // Note: because stateEmailLocalPart() is called from the 2792 // 'mailto' states (when the 'mailto' prefix itself has been 2793 // broken), make sure to set the state to EmailLocalPart 2794 stateMachine.state = 22 /* State.EmailLocalPart */; 2795 } 2796 else { 2797 // not an email address character 2798 context.removeMachine(stateMachine); 2799 } 2800} 2801// Handles the state where we've read a '.' character in the local part of 2802// the email address (i.e. the part before the '@' character) 2803function stateEmailLocalPartDot(context, stateMachine, charCode) { 2804 if (charCode === 46 /* Char.Dot */ /* '.' */) { 2805 // We read a second '.' in a row, not a valid email address 2806 // local part 2807 context.removeMachine(stateMachine); 2808 } 2809 else if (charCode === 64 /* Char.AtSign */ /* '@' */) { 2810 // We read the '@' character immediately after a dot ('.'), not 2811 // an email address 2812 context.removeMachine(stateMachine); 2813 } 2814 else if (isEmailLocalPartChar(charCode)) { 2815 stateMachine.state = 22 /* State.EmailLocalPart */; 2816 } 2817 else { 2818 // Anything else, not an email address 2819 context.removeMachine(stateMachine); 2820 } 2821} 2822function stateEmailAtSign(context, stateMachine, charCode) { 2823 if (isDomainLabelStartChar(charCode)) { 2824 stateMachine.state = 25 /* State.EmailDomainChar */; 2825 } 2826 else { 2827 // Anything else, not an email address 2828 context.removeMachine(stateMachine); 2829 } 2830} 2831function stateEmailDomainChar(context, stateMachine, charCode) { 2832 if (charCode === 46 /* Char.Dot */ /* '.' */) { 2833 stateMachine.state = 27 /* State.EmailDomainDot */; 2834 } 2835 else if (charCode === 45 /* Char.Dash */ /* '-' */) { 2836 stateMachine.state = 26 /* State.EmailDomainHyphen */; 2837 } 2838 else if (isDomainLabelChar(charCode)) ; 2839 else { 2840 // Anything else, we potentially matched if the criteria has 2841 // been met 2842 captureMatchIfValidAndRemove(context, stateMachine); 2843 } 2844} 2845function stateEmailDomainHyphen(context, stateMachine, charCode) {
vendor: 6,853 bytes, lines 2846-3020
2846 if (charCode === 45 /* Char.Dash */ /* '-' */ || charCode === 46 /* Char.Dot */ /* '.' */) { 2847 // Not valid to have two hyphens ("--") or hypen+dot ("-.") 2848 captureMatchIfValidAndRemove(context, stateMachine); 2849 } 2850 else if (isDomainLabelChar(charCode)) { 2851 stateMachine.state = 25 /* State.EmailDomainChar */; 2852 } 2853 else { 2854 // Anything else 2855 captureMatchIfValidAndRemove(context, stateMachine); 2856 } 2857} 2858function stateEmailDomainDot(context, stateMachine, charCode) { 2859 if (charCode === 46 /* Char.Dot */ /* '.' */ || charCode === 45 /* Char.Dash */ /* '-' */) { 2860 // not valid to have two dots ("..") or dot+hypen (".-") 2861 captureMatchIfValidAndRemove(context, stateMachine); 2862 } 2863 else if (isDomainLabelStartChar(charCode)) { 2864 stateMachine.state = 25 /* State.EmailDomainChar */; 2865 // After having read a '.' and then a valid domain character, 2866 // we now know that the domain part of the email is valid, and 2867 // we have found at least a partial EmailMatch (however, the 2868 // email address may have additional characters from this point) 2869 stateMachine.acceptStateReached = true; 2870 } 2871 else { 2872 // Anything else 2873 captureMatchIfValidAndRemove(context, stateMachine); 2874 } 2875} 2876// Handles the state when we've just encountered a '#' character 2877function stateHashtagHashChar(context, stateMachine, charCode) { 2878 if (isHashtagTextChar(charCode)) { 2879 // '#' char with valid hash text char following 2880 stateMachine.state = 29 /* State.HashtagTextChar */; 2881 stateMachine.acceptStateReached = true; 2882 } 2883 else { 2884 context.removeMachine(stateMachine); 2885 } 2886} 2887// Handles the state when we're currently in the hash tag's text chars 2888function stateHashtagTextChar(context, stateMachine, charCode) { 2889 if (isHashtagTextChar(charCode)) ; 2890 else { 2891 captureMatchIfValidAndRemove(context, stateMachine); 2892 } 2893} 2894// Handles the state when we've just encountered a '@' character 2895function stateMentionAtChar(context, stateMachine, charCode) { 2896 if (isMentionTextChar(charCode)) { 2897 // '@' char with valid mention text char following 2898 stateMachine.state = 31 /* State.MentionTextChar */; 2899 stateMachine.acceptStateReached = true; 2900 } 2901 else { 2902 context.removeMachine(stateMachine); 2903 } 2904} 2905// Handles the state when we're currently in the mention's text chars 2906function stateMentionTextChar(context, stateMachine, charCode) { 2907 if (isMentionTextChar(charCode)) ; 2908 else if (isAlphaNumericOrMarkChar(charCode)) { 2909 // Char is invalid for a mention text char, not a valid match. 2910 // Note that ascii alphanumeric chars are okay (which are tested 2911 // in the previous 'if' statement, but others are not) 2912 context.removeMachine(stateMachine); 2913 } 2914 else { 2915 captureMatchIfValidAndRemove(context, stateMachine); 2916 } 2917} 2918function statePhoneNumberPlus(context, stateMachine, char, charCode) { 2919 if (isDigitChar(charCode)) { 2920 stateMachine.state = 38 /* State.PhoneNumberDigit */; 2921 } 2922 else { 2923 context.removeMachine(stateMachine); 2924 // This character may start a new match. Add states for it 2925 stateNoMatch(context, char, charCode); 2926 } 2927} 2928function statePhoneNumberOpenParen(context, stateMachine, char, charCode) { 2929 if (isDigitChar(charCode)) { 2930 stateMachine.state = 33 /* State.PhoneNumberAreaCodeDigit1 */; 2931 } 2932 else { 2933 context.removeMachine(stateMachine); 2934 } 2935 // It's also possible that the paren was just an open brace for 2936 // a piece of text. Start other machines 2937 stateNoMatch(context, char, charCode); 2938} 2939function statePhoneNumberAreaCodeDigit1(context, stateMachine, charCode) { 2940 if (isDigitChar(charCode)) { 2941 stateMachine.state = 34 /* State.PhoneNumberAreaCodeDigit2 */; 2942 } 2943 else { 2944 context.removeMachine(stateMachine); 2945 } 2946} 2947function statePhoneNumberAreaCodeDigit2(context, stateMachine, charCode) { 2948 if (isDigitChar(charCode)) { 2949 stateMachine.state = 35 /* State.PhoneNumberAreaCodeDigit3 */; 2950 } 2951 else { 2952 context.removeMachine(stateMachine); 2953 } 2954} 2955function statePhoneNumberAreaCodeDigit3(context, stateMachine, charCode) { 2956 if (charCode === 41 /* Char.CloseParen */ /* ')' */) { 2957 stateMachine.state = 36 /* State.PhoneNumberCloseParen */; 2958 } 2959 else { 2960 context.removeMachine(stateMachine); 2961 } 2962} 2963function statePhoneNumberCloseParen(context, stateMachine, char, charCode) { 2964 if (isDigitChar(charCode)) { 2965 stateMachine.state = 38 /* State.PhoneNumberDigit */; 2966 } 2967 else if (isPhoneNumberSeparatorChar(charCode)) { 2968 stateMachine.state = 39 /* State.PhoneNumberSeparator */; 2969 } 2970 else { 2971 context.removeMachine(stateMachine); 2972 } 2973} 2974function statePhoneNumberDigit(context, stateMachine, char, charCode) { 2975 var charIdx = context.charIdx; 2976 // For now, if we've reached any digits, we'll say that the machine 2977 // has reached its accept state. The phone regex will confirm the 2978 // match later. 2979 // Alternatively, we could count the number of digits to avoid 2980 // invoking the phone number regex 2981 stateMachine.acceptStateReached = true; 2982 if (isPhoneNumberControlChar(charCode)) { 2983 stateMachine.state = 40 /* State.PhoneNumberControlChar */; 2984 } 2985 else if (charCode === 35 /* Char.NumberSign */ /* '#' */) { 2986 stateMachine.state = 41 /* State.PhoneNumberPoundChar */; 2987 } 2988 else if (isDigitChar(charCode)) ; 2989 else if (charCode === 40 /* Char.OpenParen */ /* '(' */) { 2990 stateMachine.state = 32 /* State.PhoneNumberOpenParen */; 2991 } 2992 else if (isPhoneNumberSeparatorChar(charCode)) { 2993 stateMachine.state = 39 /* State.PhoneNumberSeparator */; 2994 } 2995 else { 2996 captureMatchIfValidAndRemove(context, stateMachine); 2997 // The transition from a digit character to a letter can be the 2998 // start of a new scheme URL match 2999 if (isSchemeStartChar(charCode)) { 3000 context.addMachine(createSchemeUrlStateMachine(charIdx, 0 /* State.SchemeChar */)); 3001 } 3002 } 3003} 3004function statePhoneNumberSeparator(context, stateMachine, char, charCode) { 3005 if (isDigitChar(charCode)) { 3006 stateMachine.state = 38 /* State.PhoneNumberDigit */; 3007 } 3008 else if (charCode === 40 /* Char.OpenParen */ /* '(' */) { 3009 stateMachine.state = 32 /* State.PhoneNumberOpenParen */; 3010 } 3011 else { 3012 captureMatchIfValidAndRemove(context, stateMachine); 3013 // This character may start a new match. Add states for it 3014 stateNoMatch(context, char, charCode); 3015 } 3016} 3017// The ";" characters is "wait" in a phone number 3018// The "," characters is "pause" in a phone number 3019function statePhoneNumberControlChar(context, stateMachine, charCode) { 3020 if (isPhoneNumberControlChar(charCode)) ;
vendor: 9,602 bytes, lines 3020-3238
3020 3021 else if (charCode === 35 /* Char.NumberSign */ /* '#' */) { 3022 stateMachine.state = 41 /* State.PhoneNumberPoundChar */; 3023 } 3024 else if (isDigitChar(charCode)) { 3025 stateMachine.state = 38 /* State.PhoneNumberDigit */; 3026 } 3027 else { 3028 captureMatchIfValidAndRemove(context, stateMachine); 3029 } 3030} 3031// The "#" characters is "pound" in a phone number 3032function statePhoneNumberPoundChar(context, stateMachine, charCode) { 3033 if (isPhoneNumberControlChar(charCode)) { 3034 stateMachine.state = 40 /* State.PhoneNumberControlChar */; 3035 } 3036 else if (isDigitChar(charCode)) { 3037 // According to some of the older tests, if there's a digit 3038 // after a '#' sign, the match is invalid. TODO: Revisit if this is true 3039 context.removeMachine(stateMachine); 3040 } 3041 else { 3042 captureMatchIfValidAndRemove(context, stateMachine); 3043 } 3044} 3045/* 3046 * Captures a match if it is valid (i.e. has a full domain name for a 3047 * TLD match). If a match is not valid, it is possible that we want to 3048 * keep reading characters in order to make a full match. 3049 */ 3050function captureMatchIfValidAndRemove(context, stateMachine) { 3051 var matches = context.matches, text = context.text, charIdx = context.charIdx, tagBuilder = context.tagBuilder, stripPrefix = context.stripPrefix, stripTrailingSlash = context.stripTrailingSlash, decodePercentEncoding = context.decodePercentEncoding, hashtagServiceName = context.hashtagServiceName, mentionServiceName = context.mentionServiceName; 3052 // Remove the state machine first. There are a number of code paths 3053 // which return out of this function early, so make sure we have 3054 // this done 3055 context.removeMachine(stateMachine); 3056 // Make sure the state machine being checked has actually reached an 3057 // "accept" state. If it hasn't reach one, it can't be a match 3058 if (!stateMachine.acceptStateReached) { 3059 return; 3060 } 3061 var startIdx = stateMachine.startIdx; 3062 var matchedText = text.slice(stateMachine.startIdx, charIdx); 3063 // Handle any unbalanced braces (parens, square brackets, or curly 3064 // brackets) inside the URL. This handles situations like: 3065 // The link (google.com) 3066 // and 3067 // Check out this link here (en.wikipedia.org/wiki/IANA_(disambiguation)) 3068 // 3069 // And also remove any punctuation chars at the end such as: 3070 // '?', ',', ':', '.', etc. 3071 matchedText = excludeUnbalancedTrailingBracesAndPunctuation(matchedText); 3072 switch (stateMachine.type) { 3073 case 0 /* StateMachineType.Url */: { 3074 // We don't want to accidentally match a URL that is preceded by an 3075 // '@' character, which would be an email address 3076 var charBeforeUrlMatch = text.charCodeAt(stateMachine.startIdx - 1); 3077 if (charBeforeUrlMatch === 64 /* Char.AtSign */ /* '@' */) { 3078 return; 3079 } 3080 switch (stateMachine.matchType) { 3081 case 0 /* UrlStateMachineMatchType.Scheme */: { 3082 // Autolinker accepts many characters in a url's scheme (like `fake://test.com`). 3083 // However, in cases where a URL is missing whitespace before an obvious link, 3084 // (for example: `nowhitespacehttp://www.test.com`), we only want the match to start 3085 // at the http:// part. We will check if the match contains a common scheme and then 3086 // shift the match to start from there. 3087 var httpSchemeMatch = httpSchemeRe.exec(matchedText); 3088 if (httpSchemeMatch) { 3089 // If we found an overmatched URL, we want to find the index 3090 // of where the match should start and shift the match to 3091 // start from the beginning of the common scheme 3092 startIdx = startIdx + httpSchemeMatch.index; 3093 matchedText = matchedText.slice(httpSchemeMatch.index); 3094 } 3095 if (!isValidSchemeUrl(matchedText)) { 3096 return; // not a valid match 3097 } 3098 break; 3099 } 3100 case 1 /* UrlStateMachineMatchType.Tld */: { 3101 if (!isValidTldMatch(matchedText)) { 3102 return; // not a valid match 3103 } 3104 break; 3105 } 3106 case 2 /* UrlStateMachineMatchType.IpV4 */: { 3107 if (!isValidIpV4Address(matchedText)) { 3108 return; // not a valid match 3109 } 3110 break; 3111 } 3112 /* istanbul ignore next */ 3113 default: 3114 assertNever(stateMachine); 3115 } 3116 matches.push(new UrlMatch({ 3117 tagBuilder: tagBuilder, 3118 matchedText: matchedText, 3119 offset: startIdx, 3120 urlMatchType: toUrlMatchType(stateMachine.matchType), 3121 url: matchedText, 3122 protocolRelativeMatch: matchedText.slice(0, 2) === '//', 3123 // TODO: Do these settings need to be passed to the match, 3124 // or should we handle them here in UrlMatcher? 3125 stripPrefix: stripPrefix, 3126 stripTrailingSlash: stripTrailingSlash, 3127 decodePercentEncoding: decodePercentEncoding, 3128 })); 3129 break; 3130 } 3131 case 1 /* StateMachineType.Email */: { 3132 // if the email address has a valid TLD, add it to the list of matches 3133 if (isValidEmail(matchedText)) { 3134 matches.push(new EmailMatch({ 3135 tagBuilder: tagBuilder, 3136 matchedText: matchedText, 3137 offset: startIdx, 3138 email: matchedText.replace(mailtoSchemePrefixRe, ''), 3139 })); 3140 } 3141 break; 3142 } 3143 case 2 /* StateMachineType.Hashtag */: { 3144 if (isValidHashtag(matchedText)) { 3145 matches.push(new HashtagMatch({ 3146 tagBuilder: tagBuilder, 3147 matchedText: matchedText, 3148 offset: startIdx, 3149 serviceName: hashtagServiceName, 3150 hashtag: matchedText.slice(1), 3151 })); 3152 } 3153 break; 3154 } 3155 case 3 /* StateMachineType.Mention */: { 3156 if (isValidMention(matchedText, mentionServiceName)) { 3157 matches.push(new MentionMatch({ 3158 tagBuilder: tagBuilder, 3159 matchedText: matchedText, 3160 offset: startIdx, 3161 serviceName: mentionServiceName, 3162 mention: matchedText.slice(1), // strip off the '@' character at the beginning 3163 })); 3164 } 3165 break; 3166 } 3167 case 4 /* StateMachineType.Phone */: { 3168 // remove any trailing spaces that were considered as "separator" 3169 // chars by the state machine 3170 matchedText = matchedText.replace(/ +$/g, ''); 3171 if (isValidPhoneNumber(matchedText)) { 3172 var cleanNumber = matchedText.replace(/[^0-9,;#]/g, ''); // strip out non-digit characters exclude comma semicolon and # 3173 matches.push(new PhoneMatch({ 3174 tagBuilder: tagBuilder, 3175 matchedText: matchedText, 3176 offset: startIdx, 3177 number: cleanNumber, 3178 plusSign: matchedText.charAt(0) === '+', 3179 })); 3180 } 3181 break; 3182 } 3183 /* istanbul ignore next */ 3184 default: 3185 assertNever(stateMachine); 3186 } 3187} 3188/** 3189 * Helper function to convert a UrlStateMachineMatchType value to its 3190 * UrlMatchType equivalent. 3191 */ 3192function toUrlMatchType(stateMachineMatchType) { 3193 switch (stateMachineMatchType) { 3194 case 0 /* UrlStateMachineMatchType.Scheme */: 3195 return 'scheme'; 3196 case 1 /* UrlStateMachineMatchType.Tld */: 3197 return 'tld'; 3198 case 2 /* UrlStateMachineMatchType.IpV4 */: 3199 return 'ipV4'; 3200 /* istanbul ignore next */ 3201 default: 3202 assertNever(stateMachineMatchType); 3203 } 3204} 3205var oppositeBrace = { 3206 ')': '(', 3207 '}': '{', 3208 ']': '[', 3209}; 3210/** 3211 * Determines if a match found has unmatched closing parenthesis, 3212 * square brackets or curly brackets. If so, these unbalanced symbol(s) will be 3213 * removed from the URL match itself. 3214 * 3215 * A match may have an extra closing parenthesis/square brackets/curly brackets 3216 * at the end of the match because these are valid URL path characters. For 3217 * example, "wikipedia.com/something_(disambiguation)" should be auto-linked. 3218 * 3219 * However, an extra parenthesis *will* be included when the URL itself is 3220 * wrapped in parenthesis, such as in the case of: 3221 * 3222 * "(wikipedia.com/something_(disambiguation))" 3223 * 3224 * In this case, the last closing parenthesis should *not* be part of the 3225 * URL itself, and this method will exclude it from the returned URL. 3226 * 3227 * For square brackets in URLs such as in PHP arrays, the same behavior as 3228 * parenthesis discussed above should happen: 3229 * 3230 * "[http://www.example.com/foo.php?bar[]=1&bar[]=2&bar[]=3]" 3231 * 3232 * The very last closing square bracket should not be part of the URL itself, 3233 * and therefore this method will remove it. 3234 * 3235 * @param matchedText The full matched URL/email/hashtag/etc. from the state 3236 * machine parser. 3237 * @return The updated matched text with extraneous suffix characters removed. 3238 */
3239function excludeUnbalancedTrailingBracesAndPunctuation(matchedText) { 3240 var braceCounts = { 3241 '(': 0, 3242 '{': 0, 3243 '[': 0, 3244 }; 3245 for (var i = 0; i < matchedText.length; i++) { 3246 var char = matchedText.charAt(i);
vendor: 4,685 bytes, lines 3247-3386
3247 var charCode = matchedText.charCodeAt(i); 3248 if (isOpenBraceChar(charCode)) { 3249 braceCounts[char]++; 3250 } 3251 else if (isCloseBraceChar(charCode)) { 3252 braceCounts[oppositeBrace[char]]--; 3253 } 3254 } 3255 var endIdx = matchedText.length - 1; 3256 while (endIdx >= 0) { 3257 var char = matchedText.charAt(endIdx); 3258 var charCode = matchedText.charCodeAt(endIdx); 3259 if (isCloseBraceChar(charCode)) { 3260 var oppositeBraceChar = oppositeBrace[char]; 3261 if (braceCounts[oppositeBraceChar] < 0) { 3262 braceCounts[oppositeBraceChar]++; 3263 endIdx--; 3264 } 3265 else { 3266 break; 3267 } 3268 } 3269 else if (isUrlSuffixNotAllowedAsFinalChar(charCode)) { 3270 // Walk back a punctuation char like '?', ',', ':', '.', etc. 3271 endIdx--; 3272 } 3273 else { 3274 break; 3275 } 3276 } 3277 return matchedText.slice(0, endIdx + 1); 3278} 3279function createSchemeUrlStateMachine(startIdx, state) { 3280 return { 3281 type: 0 /* StateMachineType.Url */, 3282 startIdx: startIdx, 3283 state: state, 3284 acceptStateReached: false, 3285 matchType: 0 /* UrlStateMachineMatchType.Scheme */, 3286 }; 3287} 3288function createTldUrlStateMachine(startIdx, state) { 3289 return { 3290 type: 0 /* StateMachineType.Url */, 3291 startIdx: startIdx, 3292 state: state, 3293 acceptStateReached: false, 3294 matchType: 1 /* UrlStateMachineMatchType.Tld */, 3295 }; 3296} 3297function createIpV4UrlStateMachine(startIdx, state) { 3298 return { 3299 type: 0 /* StateMachineType.Url */, 3300 startIdx: startIdx, 3301 state: state, 3302 acceptStateReached: false, 3303 matchType: 2 /* UrlStateMachineMatchType.IpV4 */, 3304 octetsEncountered: 1, // starts at 1 because we create this machine when encountering the first octet 3305 }; 3306} 3307function createEmailStateMachine(startIdx, state) { 3308 return { 3309 type: 1 /* StateMachineType.Email */, 3310 startIdx: startIdx, 3311 state: state, 3312 acceptStateReached: false, 3313 }; 3314} 3315function createHashtagStateMachine(startIdx, state) { 3316 return { 3317 type: 2 /* StateMachineType.Hashtag */, 3318 startIdx: startIdx, 3319 state: state, 3320 acceptStateReached: false, 3321 }; 3322} 3323function createMentionStateMachine(startIdx, state) { 3324 return { 3325 type: 3 /* StateMachineType.Mention */, 3326 startIdx: startIdx, 3327 state: state, 3328 acceptStateReached: false, 3329 }; 3330} 3331function createPhoneNumberStateMachine(startIdx, state) { 3332 return { 3333 type: 4 /* StateMachineType.Phone */, 3334 startIdx: startIdx, 3335 state: state, 3336 acceptStateReached: false, 3337 }; 3338} 3339function isSchemeUrlStateMachine(machine) { 3340 return (machine.type === 0 /* StateMachineType.Url */ && 3341 machine.matchType === 0 /* UrlStateMachineMatchType.Scheme */); 3342} 3343 3344// For debugging: search for other "For debugging" lines 3345// import CliTable from 'cli-table'; 3346var CurrentTag = /** @class */ (function () { 3347 function CurrentTag(cfg) { 3348 if (cfg === void 0) { cfg = {}; } 3349 this.idx = cfg.idx !== undefined ? cfg.idx : -1; 3350 this.type = cfg.type || 'tag'; 3351 this.name = cfg.name || ''; 3352 this.isOpening = !!cfg.isOpening; 3353 this.isClosing = !!cfg.isClosing; 3354 } 3355 return CurrentTag; 3356}()); 3357var noCurrentTag = new CurrentTag(); // shared reference for when there is no current tag currently being read 3358/** 3359 * Context object containing all the state needed by the HTML parsing state 3360 * machine function. 3361 * 3362 * ## Historical note 3363 * 3364 * In v4.1.5, we used nested functions to handle the context via closures, but 3365 * this necessitated re-creating the functions for each call to `parseHtml()`, 3366 * which made them difficult for v8 to JIT optimize. In v4.1.6, we lifted all of 3367 * the functions to the top-level scope and passed the context object between 3368 * them, which allows the functions to be JIT compiled once and reused. 3369 */ 3370var ParseHtmlContext = /** @class */ (function () { 3371 function ParseHtmlContext(html, callbacks) { 3372 this.charIdx = 0; // Current character index being processed 3373 this.state = 0 /* State.Data */; // begin in the Data state 3374 this.currentDataIdx = 0; // where the current data start index is 3375 this.currentTag = noCurrentTag; // describes the current tag that is being read 3376 this.html = html; 3377 this.callbacks = callbacks; 3378 } 3379 return ParseHtmlContext; 3380}()); 3381/** 3382 * Parses an HTML string, calling the callbacks to notify of tags and text. 3383 * 3384 * ## History 3385 * 3386 * This file previously used a regular expression to find html tags in the input
3387 * text. Unfortunately, we ran into a bunch of catastrophic backtracking issues 3388 * with certain input text, causing Autolinker to either hang or just take a 3389 * really long time to parse the string. 3390 * 3391 * The current code is intended to be a O(n) algorithm that walks through 3392 * the string in one pass, and tries to be as cheap as possible. We don't need 3393 * to implement the full HTML spec, but rather simply determine where the string 3394 * looks like an HTML tag, and where it looks like text (so that we can autolink 3395 * that). 3396 * 3397 * This state machine parser is intended just to be a simple but performant 3398 * parser of HTML for the subset of requirements we have. We simply need to: 3399 * 3400 * 1. Determine where HTML tags are 3401 * 2. Determine the tag name (Autolinker specifically only cares about <a>, 3402 * <script>, and <style> tags, so as not to link any text within them) 3403 * 3404 * We don't need to: 3405 * 3406 * 1. Create a parse tree 3407 * 2. Auto-close tags with invalid markup 3408 * 3. etc. 3409 * 3410 * The other intention behind this is that we didn't want to add external 3411 * dependencies on the Autolinker utility which would increase its size. For 3412 * instance, adding htmlparser2 adds 125kb to the minified output file, 3413 * increasing its final size from 47kb to 172kb (at the time of writing). It 3414 * also doesn't work exactly correctly, treating the string "<3 blah blah blah" 3415 * as an HTML tag. 3416 * 3417 * Reference for HTML spec: 3418 * 3419 * https://www.w3.org/TR/html51/syntax.html#sec-tokenization 3420 * 3421 * @param {String} html The HTML to parse 3422 * @param {Object} callbacks 3423 * @param {Function} callbacks.onOpenTag Callback function to call when an open 3424 * tag is parsed. Called with the tagName as its argument. 3425 * @param {Function} callbacks.onCloseTag Callback function to call when a close 3426 * tag is parsed. Called with the tagName as its argument. If a self-closing 3427 * tag is found, `onCloseTag` is called immediately after `onOpenTag`. 3428 * @param {Function} callbacks.onText Callback function to call when text (i.e 3429 * not an HTML tag) is parsed. Called with the text (string) as its first 3430 * argument, and offset (number) into the string as its second. 3431 */ 3432function parseHtml(html, callbacks) { 3433 var context = new ParseHtmlContext(html, callbacks); 3434 // For debugging: search for other "For debugging" lines 3435 // const table = new CliTable( { 3436 // head: [ 'charIdx', 'char', 'state', 'currentDataIdx', 'currentOpenTagIdx', 'tag.type' ] 3437 // } ); 3438 var len = html.length; 3439 while (context.charIdx < len) { 3440 var char = html.charAt(context.charIdx); 3441 var charCode = html.charCodeAt(context.charIdx); 3442 // For debugging: search for other "For debugging" lines 3443 // ALSO: Temporarily remove the 'const' keyword on the State enum 3444 // table.push([ 3445 // String(charIdx), 3446 // char, 3447 // State[state], 3448 // String(currentDataIdx), 3449 // String(currentTag.idx), 3450 // currentTag.idx === -1 ? '' : currentTag.type 3451 // ]); 3452 switch (context.state) { 3453 case 0 /* State.Data */: 3454 stateData(context, char); 3455 break; 3456 case 1 /* State.TagOpen */: 3457 stateTagOpen(context, char, charCode); 3458 break; 3459 case 2 /* State.EndTagOpen */: 3460 stateEndTagOpen(context, char, charCode); 3461 break; 3462 case 3 /* State.TagName */: 3463 stateTagName(context, char, charCode); 3464 break; 3465 case 4 /* State.BeforeAttributeName */: 3466 stateBeforeAttributeName(context, char, charCode); 3467 break; 3468 case 5 /* State.AttributeName */: 3469 stateAttributeName(context, char, charCode); 3470 break; 3471 case 6 /* State.AfterAttributeName */: 3472 stateAfterAttributeName(context, char, charCode); 3473 break; 3474 case 7 /* State.BeforeAttributeValue */: 3475 stateBeforeAttributeValue(context, char, charCode); 3476 break; 3477 case 8 /* State.AttributeValueDoubleQuoted */: 3478 stateAttributeValueDoubleQuoted(context, char); 3479 break; 3480 case 9 /* State.AttributeValueSingleQuoted */: 3481 stateAttributeValueSingleQuoted(context, char); 3482 break; 3483 case 10 /* State.AttributeValueUnquoted */: 3484 stateAttributeValueUnquoted(context, char, charCode); 3485 break; 3486 case 11 /* State.AfterAttributeValueQuoted */: 3487 stateAfterAttributeValueQuoted(context, char, charCode); 3488 break; 3489 case 12 /* State.SelfClosingStartTag */: 3490 stateSelfClosingStartTag(context, char); 3491 break; 3492 case 13 /* State.MarkupDeclarationOpenState */: 3493 stateMarkupDeclarationOpen(context); 3494 break; 3495 case 14 /* State.CommentStart */: 3496 stateCommentStart(context, char); 3497 break; 3498 case 15 /* State.CommentStartDash */: 3499 stateCommentStartDash(context, char); 3500 break; 3501 case 16 /* State.Comment */: 3502 stateComment(context, char); 3503 break; 3504 case 17 /* State.CommentEndDash */: 3505 stateCommentEndDash(context, char); 3506 break; 3507 case 18 /* State.CommentEnd */: 3508 stateCommentEnd(context, char); 3509 break; 3510 case 19 /* State.CommentEndBang */: 3511 stateCommentEndBang(context, char); 3512 break; 3513 case 20 /* State.Doctype */: 3514 stateDoctype(context, char); 3515 break; 3516 /* istanbul ignore next */ 3517 default: 3518 assertNever(context.state); 3519 } 3520 // For debugging: search for other "For debugging" lines 3521 // ALSO: Temporarily remove the 'const' keyword on the State enum 3522 // table.push([ 3523 // String(context.charIdx), 3524 // char, 3525 // State[context.state], 3526 // String(context.currentDataIdx), 3527 // String(context.currentTag.idx), 3528 // context.currentTag.idx === -1 ? '' : context.currentTag.type 3529 // ]); 3530 context.charIdx++; 3531 } 3532 if (context.currentDataIdx < context.charIdx) { 3533 emitText(context); 3534 } 3535 // For debugging: search for other "For debugging" lines 3536 // console.log( '\n' + table.toString() ); 3537} 3538// Called when non-tags are being read (i.e. the text around HTML â ags) 3539// https://www.w3.org/TR/html51/syntax.html#data-state 3540function stateData(context, char) { 3541 if (char === '<') { 3542 startNewTag(context); 3543 } 3544} 3545// Called after a '<' is read from the Data state 3546// https://www.w3.org/TR/html51/syntax.html#tag-open-state 3547function stateTagOpen(context, char, charCode) { 3548 if (char === '!') { 3549 context.state = 13 /* State.MarkupDeclarationOpenState */; 3550 } 3551 else if (char === '/') {
vendor: 17,431 bytes, lines 3552-3992
3552 context.state = 2 /* State.EndTagOpen */; 3553 context.currentTag = new CurrentTag(__assign(__assign({}, context.currentTag), { isClosing: true })); 3554 } 3555 else if (char === '<') { 3556 // start of another tag (ignore the previous, incomplete one) 3557 startNewTag(context); 3558 } 3559 else if (isAsciiLetterChar(charCode)) { 3560 // tag name start (and no '/' read) 3561 context.state = 3 /* State.TagName */; 3562 context.currentTag = new CurrentTag(__assign(__assign({}, context.currentTag), { isOpening: true })); 3563 } 3564 else { 3565 // Any other 3566 context.state = 0 /* State.Data */; 3567 context.currentTag = noCurrentTag; 3568 } 3569} 3570// After a '<x', '</x' sequence is read (where 'x' is a letter character), 3571// this is to continue reading the tag name 3572// https://www.w3.org/TR/html51/syntax.html#tag-name-state 3573function stateTagName(context, char, charCode) { 3574 if (isWhitespaceChar(charCode)) { 3575 context.currentTag = new CurrentTag(__assign(__assign({}, context.currentTag), { name: captureTagName(context) })); 3576 context.state = 4 /* State.BeforeAttributeName */; 3577 } 3578 else if (char === '<') { 3579 // start of another tag (ignore the previous, incomplete one) 3580 startNewTag(context); 3581 } 3582 else if (char === '/') { 3583 context.currentTag = new CurrentTag(__assign(__assign({}, context.currentTag), { name: captureTagName(context) })); 3584 context.state = 12 /* State.SelfClosingStartTag */; 3585 } 3586 else if (char === '>') { 3587 context.currentTag = new CurrentTag(__assign(__assign({}, context.currentTag), { name: captureTagName(context) })); 3588 emitTagAndPreviousTextNode(context); // resets to Data state as well 3589 } 3590 else if (!isAsciiLetterChar(charCode) && !isDigitChar(charCode) && char !== ':') { 3591 // Anything else that does not form an html tag. Note: the colon 3592 // character is accepted for XML namespaced tags 3593 resetToDataState(context); 3594 } 3595 else ; 3596} 3597// Called after the '/' is read from a '</' sequence 3598// https://www.w3.org/TR/html51/syntax.html#end-tag-open-state 3599function stateEndTagOpen(context, char, charCode) { 3600 if (char === '>') { 3601 // parse error. Encountered "</>". Skip it without treating as a tag 3602 resetToDataState(context); 3603 } 3604 else if (isAsciiLetterChar(charCode)) { 3605 context.state = 3 /* State.TagName */; 3606 } 3607 else { 3608 // some other non-tag-like character, don't treat this as a tag 3609 resetToDataState(context); 3610 } 3611} 3612// https://www.w3.org/TR/html51/syntax.html#before-attribute-name-state 3613function stateBeforeAttributeName(context, char, charCode) { 3614 if (isWhitespaceChar(charCode)) ; 3615 else if (char === '/') { 3616 context.state = 12 /* State.SelfClosingStartTag */; 3617 } 3618 else if (char === '>') { 3619 emitTagAndPreviousTextNode(context); // resets to Data state as well 3620 } 3621 else if (char === '<') { 3622 // start of another tag (ignore the previous, incomplete one) 3623 startNewTag(context); 3624 } 3625 else if (char === "=" || isQuoteChar(charCode) || isControlChar(charCode)) { 3626 // "Parse error" characters that, according to the spec, should be 3627 // appended to the attribute name, but we'll treat these characters 3628 // as not forming a real HTML tag 3629 resetToDataState(context); 3630 } 3631 else { 3632 // Any other char, start of a new attribute name 3633 context.state = 5 /* State.AttributeName */; 3634 } 3635} 3636// https://www.w3.org/TR/html51/syntax.html#attribute-name-state 3637function stateAttributeName(context, char, charCode) { 3638 if (isWhitespaceChar(charCode)) { 3639 context.state = 6 /* State.AfterAttributeName */; 3640 } 3641 else if (char === '/') { 3642 context.state = 12 /* State.SelfClosingStartTag */; 3643 } 3644 else if (char === '=') { 3645 context.state = 7 /* State.BeforeAttributeValue */; 3646 } 3647 else if (char === '>') { 3648 emitTagAndPreviousTextNode(context); // resets to Data state as well 3649 } 3650 else if (char === '<') { 3651 // start of another tag (ignore the previous, incomplete one) 3652 startNewTag(context); 3653 } 3654 else if (isQuoteChar(charCode)) { 3655 // "Parse error" characters that, according to the spec, should be 3656 // appended to the attribute name, but we'll treat these characters 3657 // as not forming a real HTML tag 3658 resetToDataState(context); 3659 } 3660 else ; 3661} 3662// https://www.w3.org/TR/html51/syntax.html#after-attribute-name-state 3663function stateAfterAttributeName(context, char, charCode) { 3664 if (isWhitespaceChar(charCode)) ; 3665 else if (char === '/') { 3666 context.state = 12 /* State.SelfClosingStartTag */; 3667 } 3668 else if (char === '=') { 3669 context.state = 7 /* State.BeforeAttributeValue */; 3670 } 3671 else if (char === '>') { 3672 emitTagAndPreviousTextNode(context); 3673 } 3674 else if (char === '<') { 3675 // start of another tag (ignore the previous, incomplete one) 3676 startNewTag(context); 3677 } 3678 else if (isQuoteChar(charCode)) { 3679 // "Parse error" characters that, according to the spec, should be 3680 // appended to the attribute name, but we'll treat these characters 3681 // as not forming a real HTML tag 3682 resetToDataState(context); 3683 } 3684 else { 3685 // Any other character, start a new attribute in the current tag 3686 context.state = 5 /* State.AttributeName */; 3687 } 3688} 3689// https://www.w3.org/TR/html51/syntax.html#before-attribute-value-state 3690function stateBeforeAttributeValue(context, char, charCode) { 3691 if (isWhitespaceChar(charCode)) ; 3692 else if (char === "\"") { 3693 context.state = 8 /* State.AttributeValueDoubleQuoted */; 3694 } 3695 else if (char === "'") { 3696 context.state = 9 /* State.AttributeValueSingleQuoted */; 3697 } 3698 else if (/[>=`]/.test(char)) { 3699 // Invalid chars after an '=' for an attribute value, don't count 3700 // the current tag as an HTML tag 3701 resetToDataState(context); 3702 } 3703 else if (char === '<') { 3704 // start of another tag (ignore the previous, incomplete one) 3705 startNewTag(context); 3706 } 3707 else { 3708 // Any other character, consider it an unquoted attribute value 3709 context.state = 10 /* State.AttributeValueUnquoted */; 3710 } 3711} 3712// https://www.w3.org/TR/html51/syntax.html#attribute-value-double-quoted-state 3713function stateAttributeValueDoubleQuoted(context, char) { 3714 if (char === "\"") { 3715 // end the current double-quoted attribute 3716 context.state = 11 /* State.AfterAttributeValueQuoted */; 3717 } 3718} 3719// https://www.w3.org/TR/html51/syntax.html#attribute-value-single-quoted-state 3720function stateAttributeValueSingleQuoted(context, char) { 3721 if (char === "'") { 3722 // end the current single-quoted attribute 3723 context.state = 11 /* State.AfterAttributeValueQuoted */; 3724 } 3725} 3726// https://www.w3.org/TR/html51/syntax.html#attribute-value-unquoted-state 3727function stateAttributeValueUnquoted(context, char, charCode) { 3728 if (isWhitespaceChar(charCode)) { 3729 context.state = 4 /* State.BeforeAttributeName */; 3730 } 3731 else if (char === '>') { 3732 emitTagAndPreviousTextNode(context); 3733 } 3734 else if (char === '<') { 3735 // start of another tag (ignore the previous, incomplete one) 3736 startNewTag(context); 3737 } 3738 else ; 3739} 3740// Called after a double-quoted or single-quoted attribute value is read 3741// (i.e. after the closing quote character) 3742// https://www.w3.org/TR/html51/syntax.html#after-attribute-value-quoted-state 3743function stateAfterAttributeValueQuoted(context, char, charCode) { 3744 if (isWhitespaceChar(charCode)) { 3745 context.state = 4 /* State.BeforeAttributeName */; 3746 } 3747 else if (char === '/') { 3748 context.state = 12 /* State.SelfClosingStartTag */; 3749 } 3750 else if (char === '>') { 3751 emitTagAndPreviousTextNode(context); 3752 } 3753 else if (char === '<') { 3754 // start of another tag (ignore the previous, incomplete one) 3755 startNewTag(context); 3756 } 3757 else { 3758 // Any other character, "parse error". Spec says to switch to the 3759 // BeforeAttributeState and re-consume the character, as it may be 3760 // the start of a new attribute name 3761 context.state = 4 /* State.BeforeAttributeName */; 3762 reconsumeCurrentChar(context); 3763 } 3764} 3765// A '/' has just been read in the current tag (presumably for '/>'), and 3766// this handles the next character 3767// https://www.w3.org/TR/html51/syntax.html#self-closing-start-tag-state 3768function stateSelfClosingStartTag(context, char) { 3769 if (char === '>') { 3770 context.currentTag = new CurrentTag(__assign(__assign({}, context.currentTag), { isClosing: true })); 3771 emitTagAndPreviousTextNode(context); // resets to Data state as well 3772 } 3773 else { 3774 // Note: the spec calls for a character after a '/' within a start 3775 // tag to go back into the BeforeAttributeName state (in order to 3776 // read more attributes, but for the purposes of Autolinker, this is 3777 // most likely not a valid HTML tag. For example: "<something / other>" 3778 // state = State.BeforeAttributeName; 3779 // Instead, just treat as regular text 3780 resetToDataState(context); 3781 } 3782} 3783// https://www.w3.org/TR/html51/syntax.html#markup-declaration-open-state 3784// (HTML Comments or !DOCTYPE) 3785function stateMarkupDeclarationOpen(context) { 3786 var html = context.html, charIdx = context.charIdx; 3787 if (html.slice(charIdx, charIdx + 2) === '--') { 3788 // html comment 3789 context.charIdx++; // "consume" the second '-' character. Next loop iteration will consume the character after the '<!--' sequence 3790 context.currentTag = new CurrentTag(__assign(__assign({}, context.currentTag), { type: 'comment' })); 3791 context.state = 14 /* State.CommentStart */; 3792 } 3793 else if (html.slice(charIdx, charIdx + 7).toUpperCase() === 'DOCTYPE') { 3794 context.charIdx += 6; // "consume" the characters "OCTYPE" (the current loop iteraction consumed the 'D'). Next loop iteration will consume the character after the '<!DOCTYPE' sequence 3795 context.currentTag = new CurrentTag(__assign(__assign({}, context.currentTag), { type: 'doctype' })); 3796 context.state = 20 /* State.Doctype */; 3797 } 3798 else { 3799 // At this point, the spec specifies that the state machine should 3800 // enter the "bogus comment" state, in which case any character(s) 3801 // after the '<!' that were read should become an HTML comment up 3802 // until the first '>' that is read (or EOF). Instead, we'll assume 3803 // that a user just typed '<!' as part of some piece of non-html 3804 // text 3805 resetToDataState(context); 3806 } 3807} 3808// Handles after the sequence '<!--' has been read 3809// https://www.w3.org/TR/html51/syntax.html#comment-start-state 3810function stateCommentStart(context, char) { 3811 if (char === '-') { 3812 // We've read the sequence '<!---' at this point (3 dashes) 3813 context.state = 15 /* State.CommentStartDash */; 3814 } 3815 else if (char === '>') { 3816 // At this point, we'll assume the comment wasn't a real comment 3817 // so we'll just emit it as data. We basically read the sequence 3818 // '<!-->' 3819 resetToDataState(context); 3820 } 3821 else { 3822 // Any other char, take it as part of the comment 3823 context.state = 16 /* State.Comment */; 3824 } 3825} 3826// We've read the sequence '<!---' at this point (3 dashes) 3827// https://www.w3.org/TR/html51/syntax.html#comment-start-dash-state 3828function stateCommentStartDash(context, char) { 3829 if (char === '-') { 3830 // We've read '<!----' (4 dashes) at this point 3831 context.state = 18 /* State.CommentEnd */; 3832 } 3833 else if (char === '>') { 3834 // At this point, we'll assume the comment wasn't a real comment 3835 // so we'll just emit it as data. We basically read the sequence 3836 // '<!--->' 3837 resetToDataState(context); 3838 } 3839 else { 3840 // Anything else, take it as a valid comment 3841 context.state = 16 /* State.Comment */; 3842 } 3843} 3844// Currently reading the comment's text (data) 3845// https://www.w3.org/TR/html51/syntax.html#comment-state 3846function stateComment(context, char) { 3847 if (char === '-') { 3848 context.state = 17 /* State.CommentEndDash */; 3849 } 3850} 3851// When we we've read the first dash inside a comment, it may signal the 3852// end of the comment if we read another dash 3853// https://www.w3.org/TR/html51/syntax.html#comment-end-dash-state 3854function stateCommentEndDash(context, char) { 3855 if (char === '-') { 3856 context.state = 18 /* State.CommentEnd */; 3857 } 3858 else { 3859 // Wasn't a dash, must still be part of the comment 3860 context.state = 16 /* State.Comment */; 3861 } 3862} 3863// After we've read two dashes inside a comment, it may signal the end of 3864// the comment if we then read a '>' char 3865// https://www.w3.org/TR/html51/syntax.html#comment-end-state 3866function stateCommentEnd(context, char) { 3867 if (char === '>') { 3868 emitTagAndPreviousTextNode(context); 3869 } 3870 else if (char === '!') { 3871 context.state = 19 /* State.CommentEndBang */; 3872 } 3873 else if (char === '-') ; 3874 else { 3875 // Anything else, switch back to the comment state since we didn't 3876 // read the full "end comment" sequence (i.e. '-->') 3877 context.state = 16 /* State.Comment */; 3878 } 3879} 3880// We've read the sequence '--!' inside of a comment 3881// https://www.w3.org/TR/html51/syntax.html#comment-end-bang-state 3882function stateCommentEndBang(context, char) { 3883 if (char === '-') { 3884 // We read the sequence '--!-' inside of a comment. The last dash 3885 // could signify that the comment is going to close 3886 context.state = 17 /* State.CommentEndDash */; 3887 } 3888 else if (char === '>') { 3889 // End of comment with the sequence '--!>' 3890 emitTagAndPreviousTextNode(context); 3891 } 3892 else { 3893 // The '--!' was not followed by a '>', continue reading the 3894 // comment's text 3895 context.state = 16 /* State.Comment */; 3896 } 3897} 3898/** 3899 * For DOCTYPES in particular, we don't care about the attributes. Just 3900 * advance to the '>' character and emit the tag, unless we find a '<' 3901 * character in which case we'll start a new tag. 3902 * 3903 * Example doctype tag: 3904 * <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 3905 * 3906 * Actual spec: https://www.w3.org/TR/html51/syntax.html#doctype-state 3907 */ 3908function stateDoctype(context, char) { 3909 if (char === '>') { 3910 emitTagAndPreviousTextNode(context); 3911 } 3912 else if (char === '<') { 3913 startNewTag(context); 3914 } 3915 else ; 3916} 3917/** 3918 * Resets the state back to the Data state, and removes the current tag. 3919 * 3920 * We'll generally run this function whenever a "parse error" is 3921 * encountered, where the current tag that is being read no longer looks 3922 * like a real HTML tag. 3923 */ 3924function resetToDataState(context) { 3925 context.state = 0 /* State.Data */; 3926 context.currentTag = noCurrentTag; 3927} 3928/** 3929 * Starts a new HTML tag at the current index, ignoring any previous HTML 3930 * tag that was being read. 3931 * 3932 * We'll generally run this function whenever we read a new '<' character, 3933 * including when we read a '<' character inside of an HTML tag that we were 3934 * previously reading. 3935 */ 3936function startNewTag(context) { 3937 context.state = 1 /* State.TagOpen */; 3938 context.currentTag = new CurrentTag({ idx: context.charIdx }); 3939} 3940/** 3941 * Once we've decided to emit an open tag, that means we can also emit the 3942 * text node before it. 3943 */ 3944function emitTagAndPreviousTextNode(context) { 3945 var textBeforeTag = context.html.slice(context.currentDataIdx, context.currentTag.idx); 3946 if (textBeforeTag) { 3947 // the html tag was the first element in the html string, or two 3948 // tags next to each other, in which case we should not emit a text 3949 // node 3950 context.callbacks.onText(textBeforeTag, context.currentDataIdx); 3951 } 3952 var currentTag = context.currentTag; 3953 if (currentTag.type === 'comment') { 3954 context.callbacks.onComment(currentTag.idx); 3955 } 3956 else if (currentTag.type === 'doctype') { 3957 context.callbacks.onDoctype(currentTag.idx); 3958 } 3959 else { 3960 if (currentTag.isOpening) { 3961 context.callbacks.onOpenTag(currentTag.name, currentTag.idx); 3962 } 3963 if (currentTag.isClosing) { 3964 // note: self-closing tags will emit both opening and closing 3965 context.callbacks.onCloseTag(currentTag.name, currentTag.idx); 3966 } 3967 } 3968 // Since we just emitted a tag, reset to the data state for the next char 3969 resetToDataState(context); 3970 context.currentDataIdx = context.charIdx + 1; 3971} 3972function emitText(context) { 3973 var text = context.html.slice(context.currentDataIdx, context.charIdx); 3974 context.callbacks.onText(text, context.currentDataIdx); 3975 context.currentDataIdx = context.charIdx + 1; 3976} 3977/** 3978 * Captures the tag name from the start of the tag to the current character 3979 * index, and converts it to lower case 3980 */ 3981function captureTagName(context) { 3982 var startIdx = context.currentTag.idx + (context.currentTag.isClosing ? 2 : 1); 3983 return context.html.slice(startIdx, context.charIdx).toLowerCase(); 3984} 3985/** 3986 * Causes the main loop to re-consume the current character, such as after 3987 * encountering a "parse error" that changed state and needs to reconsume 3988 * the same character in that new state. 3989 */ 3990function reconsumeCurrentChar(context) { 3991 context.charIdx--; 3992}
vendor: 38,308 bytes, lines 3993-4805
3993 3994/** 3995 * @class Autolinker 3996 * @extends Object 3997 * 3998 * Utility class used to process a given string of text, and wrap the matches in 3999 * the appropriate anchor (<a>) tags to turn them into links. 4000 * 4001 * Any of the configuration options may be provided in an Object provided 4002 * to the Autolinker constructor, which will configure how the {@link #link link()} 4003 * method will process the links. 4004 * 4005 * For example: 4006 * 4007 * var autolinker = new Autolinker( { 4008 * newWindow : false, 4009 * truncate : 30 4010 * } ); 4011 * 4012 * var html = autolinker.link( "Joe went to www.yahoo.com" ); 4013 * // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>' 4014 * 4015 * 4016 * The {@link #static-link static link()} method may also be used to inline 4017 * options into a single call, which may be more convenient for one-off uses. 4018 * For example: 4019 * 4020 * var html = Autolinker.link( "Joe went to www.yahoo.com", { 4021 * newWindow : false, 4022 * truncate : 30 4023 * } ); 4024 * // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>' 4025 * 4026 * 4027 * ## Custom Replacements of Links 4028 * 4029 * If the configuration options do not provide enough flexibility, a {@link #replaceFn} 4030 * may be provided to fully customize the output of Autolinker. This function is 4031 * called once for each URL/Email/Phone#/Hashtag/Mention (Twitter, Instagram, Soundcloud) 4032 * match that is encountered. 4033 * 4034 * For example: 4035 * 4036 * var input = "..."; // string with URLs, Email Addresses, Phone #s, Hashtags, and Mentions (Twitter, Instagram, Soundcloud) 4037 * 4038 * var linkedText = Autolinker.link( input, { 4039 * replaceFn : function( match ) { 4040 * console.log( "href = ", match.getAnchorHref() ); 4041 * console.log( "text = ", match.getAnchorText() ); 4042 * 4043 * switch( match.getType() ) { 4044 * case 'url' : 4045 * console.log( "url: ", match.getUrl() ); 4046 * 4047 * if( match.getUrl().indexOf( 'mysite.com' ) === -1 ) { 4048 * var tag = match.buildTag(); // returns an `Autolinker.HtmlTag` instance, which provides mutator methods for easy changes 4049 * tag.setAttr( 'rel', 'nofollow' ); 4050 * tag.addClass( 'external-link' ); 4051 * 4052 * return tag; 4053 * 4054 * } else { 4055 * return true; // let Autolinker perform its normal anchor tag replacement 4056 * } 4057 * 4058 * case 'email' : 4059 * var email = match.getEmail(); 4060 * console.log( "email: ", email ); 4061 * 4062 * if( email === "[email protected]" ) { 4063 * return false; // don't auto-link this particular email address; leave as-is 4064 * } else { 4065 * return; // no return value will have Autolinker perform its normal anchor tag replacement (same as returning `true`) 4066 * } 4067 * 4068 * case 'phone' : 4069 * var phoneNumber = match.getPhoneNumber(); 4070 * console.log( phoneNumber ); 4071 * 4072 * return '<a href="http://newplace.to.link.phone.numbers.to/">' + phoneNumber + '</a>'; 4073 * 4074 * case 'hashtag' : 4075 * var hashtag = match.getHashtag(); 4076 * console.log( hashtag ); 4077 * 4078 * return '<a href="http://newplace.to.link.hashtag.handles.to/">' + hashtag + '</a>'; 4079 * 4080 * case 'mention' : 4081 * var mention = match.getMention(); 4082 * console.log( mention ); 4083 * 4084 * return '<a href="http://newplace.to.link.mention.to/">' + mention + '</a>'; 4085 * } 4086 * } 4087 * } ); 4088 * 4089 * 4090 * The function may return the following values: 4091 * 4092 * - `true` (Boolean): Allow Autolinker to replace the match as it normally 4093 * would. 4094 * - `false` (Boolean): Do not replace the current match at all - leave as-is. 4095 * - Any String: If a string is returned from the function, the string will be 4096 * used directly as the replacement HTML for the match. 4097 * - An {@link Autolinker.HtmlTag} instance, which can be used to build/modify 4098 * an HTML tag before writing out its HTML text. 4099 */ 4100var Autolinker = /** @class */ (function () { 4101 /** 4102 * @method constructor 4103 * @param {Object} [cfg] The configuration options for the Autolinker instance, 4104 * specified in an Object (map). 4105 */ 4106 function Autolinker(cfg) { 4107 if (cfg === void 0) { cfg = {}; } 4108 /** 4109 * The Autolinker version number exposed on the instance itself. 4110 * 4111 * Ex: 0.25.1 4112 * 4113 * @property {String} version 4114 */ 4115 this.version = Autolinker.version; 4116 /** 4117 * @cfg {Boolean/Object} [urls] 4118 * 4119 * `true` if URLs should be automatically linked, `false` if they should not 4120 * be. Defaults to `true`. 4121 * 4122 * Examples: 4123 * 4124 * urls: true 4125 * 4126 * // or 4127 * 4128 * urls: { 4129 * schemeMatches : true, 4130 * tldMatches : true, 4131 * ipV4Matches : true 4132 * } 4133 * 4134 * As shown above, this option also accepts an Object form with 3 properties 4135 * to allow for more customization of what exactly gets linked. All default 4136 * to `true`: 4137 * 4138 * @cfg {Boolean} [urls.schemeMatches] `true` to match URLs found prefixed 4139 * with a scheme, i.e. `http://google.com`, or `other+scheme://google.com`, 4140 * `false` to prevent these types of matches. 4141 * @cfg {Boolean} [urls.tldMatches] `true` to match URLs with known top 4142 * level domains (.com, .net, etc.) that are not prefixed with a scheme 4143 * (such as 'http://'). This option attempts to match anything that looks 4144 * like a URL in the given text. Ex: `google.com`, `asdf.org/?page=1`, etc. 4145 * `false` to prevent these types of matches. 4146 * @cfg {Boolean} [urls.ipV4Matches] `true` to match IPv4 addresses in text 4147 * that are not prefixed with a scheme (such as 'http://'). This option 4148 * attempts to match anything that looks like an IPv4 address in text. Ex: 4149 * `192.168.0.1`, `10.0.0.1/?page=1`, etc. `false` to prevent these types 4150 * of matches. 4151 */ 4152 this.urls = {}; // default value just to get the above doc comment in the ES5 output and documentation generator 4153 /** 4154 * @cfg {Boolean} [email=true] 4155 * 4156 * `true` if email addresses should be automatically linked, `false` if they 4157 * should not be. 4158 */ 4159 this.email = true; // default value just to get the above doc comment in the ES5 output and documentation generator 4160 /** 4161 * @cfg {Boolean} [phone=true] 4162 * 4163 * `true` if Phone numbers ("(555)555-5555") should be automatically linked, 4164 * `false` if they should not be. 4165 */ 4166 this.phone = true; // default value just to get the above doc comment in the ES5 output and documentation generator 4167 /** 4168 * @cfg {Boolean/String} [hashtag=false] 4169 * 4170 * A string for the service name to have hashtags (ex: "#myHashtag") 4171 * auto-linked to. The currently-supported values are: 4172 * 4173 * - 'twitter' 4174 * - 'facebook' 4175 * - 'instagram' 4176 * - 'tiktok' 4177 * - 'youtube' 4178 * 4179 * Pass `false` to skip auto-linking of hashtags. 4180 */ 4181 this.hashtag = false; // default value just to get the above doc comment in the ES5 output and documentation generator 4182 /** 4183 * @cfg {String/Boolean} [mention=false] 4184 * 4185 * A string for the service name to have mentions (ex: "@myuser") 4186 * auto-linked to. The currently supported values are: 4187 * 4188 * - 'twitter' 4189 * - 'instagram' 4190 * - 'soundcloud' 4191 * - 'tiktok' 4192 * - 'youtube' 4193 * 4194 * Defaults to `false` to skip auto-linking of mentions. 4195 */ 4196 this.mention = false; // default value just to get the above doc comment in the ES5 output and documentation generator 4197 /** 4198 * @cfg {Boolean} [newWindow=true] 4199 * 4200 * `true` if the links should open in a new window, `false` otherwise. 4201 */ 4202 this.newWindow = true; // default value just to get the above doc comment in the ES5 output and documentation generator 4203 /** 4204 * @cfg {Boolean/Object} [stripPrefix=true] 4205 * 4206 * `true` if 'http://' (or 'https://') and/or the 'www.' should be stripped 4207 * from the beginning of URL links' text, `false` otherwise. Defaults to 4208 * `true`. 4209 * 4210 * Examples: 4211 * 4212 * stripPrefix: true 4213 * 4214 * // or 4215 * 4216 * stripPrefix: { 4217 * scheme : true, 4218 * www : true 4219 * } 4220 * 4221 * As shown above, this option also accepts an Object form with 2 properties 4222 * to allow for more customization of what exactly is prevented from being 4223 * displayed. Both default to `true`: 4224 * 4225 * @cfg {Boolean} [stripPrefix.scheme] `true` to prevent the scheme part of 4226 * a URL match from being displayed to the user. Example: 4227 * `'http://google.com'` will be displayed as `'google.com'`. `false` to 4228 * not strip the scheme. NOTE: Only an `'http://'` or `'https://'` scheme 4229 * will be removed, so as not to remove a potentially dangerous scheme 4230 * (such as `'file://'` or `'javascript:'`) 4231 * @cfg {Boolean} [stripPrefix.www] www (Boolean): `true` to prevent the 4232 * `'www.'` part of a URL match from being displayed to the user. Ex: 4233 * `'www.google.com'` will be displayed as `'google.com'`. `false` to not 4234 * strip the `'www'`. 4235 */ 4236 this.stripPrefix = { 4237 scheme: true, 4238 www: true, 4239 }; // default value just to get the above doc comment in the ES5 output and documentation generator 4240 /** 4241 * @cfg {Boolean} [stripTrailingSlash=true] 4242 * 4243 * `true` to remove the trailing slash from URL matches, `false` to keep 4244 * the trailing slash. 4245 * 4246 * Example when `true`: `http://google.com/` will be displayed as 4247 * `http://google.com`. 4248 */ 4249 this.stripTrailingSlash = true; // default value just to get the above doc comment in the ES5 output and documentation generator 4250 /** 4251 * @cfg {Boolean} [decodePercentEncoding=true] 4252 * 4253 * `true` to decode percent-encoded characters in URL matches, `false` to keep 4254 * the percent-encoded characters. 4255 * 4256 * Example when `true`: `https://en.wikipedia.org/wiki/San_Jos%C3%A9` will 4257 * be displayed as `https://en.wikipedia.org/wiki/San_José`. 4258 */ 4259 this.decodePercentEncoding = true; // default value just to get the above doc comment in the ES5 output and documentation generator 4260 /** 4261 * @cfg {Number/Object} [truncate=0] 4262 * 4263 * ## Number Form 4264 * 4265 * A number for how many characters matched text should be truncated to 4266 * inside the text of a link. If the matched text is over this number of 4267 * characters, it will be truncated to this length by adding a two period 4268 * ellipsis ('..') to the end of the string. 4269 * 4270 * For example: A url like 'http://www.yahoo.com/some/long/path/to/a/file' 4271 * truncated to 25 characters might look something like this: 4272 * 'yahoo.com/some/long/pat..' 4273 * 4274 * Example Usage: 4275 * 4276 * truncate: 25 4277 * 4278 * 4279 * Defaults to `0` for "no truncation." 4280 * 4281 * 4282 * ## Object Form 4283 * 4284 * An Object may also be provided with two properties: `length` (Number) and 4285 * `location` (String). `location` may be one of the following: 'end' 4286 * (default), 'middle', or 'smart'. 4287 * 4288 * Example Usage: 4289 * 4290 * truncate: { length: 25, location: 'middle' } 4291 * 4292 * @cfg {Number} [truncate.length=0] How many characters to allow before 4293 * truncation will occur. Defaults to `0` for "no truncation." 4294 * @cfg {"end"/"middle"/"smart"} [truncate.location="end"] 4295 * 4296 * - 'end' (default): will truncate up to the number of characters, and then 4297 * add an ellipsis at the end. Ex: 'yahoo.com/some/long/pat..' 4298 * - 'middle': will truncate and add the ellipsis in the middle. Ex: 4299 * 'yahoo.com/s..th/to/a/file' 4300 * - 'smart': for URLs where the algorithm attempts to strip out unnecessary 4301 * parts first (such as the 'www.', then URL scheme, hash, etc.), 4302 * attempting to make the URL human-readable before looking for a good 4303 * point to insert the ellipsis if it is still too long. Ex: 4304 * 'yahoo.com/some..to/a/file'. For more details, see 4305 * {@link Autolinker.truncate.TruncateSmart}. 4306 */ 4307 this.truncate = { 4308 length: 0, 4309 location: 'end', 4310 }; // default value just to get the above doc comment in the ES5 output and documentation generator 4311 /** 4312 * @cfg {String} className 4313 * 4314 * A CSS class name to add to the generated links. This class will be added 4315 * to all links, as well as this class plus match suffixes for styling 4316 * url/email/phone/hashtag/mention links differently. 4317 * 4318 * For example, if this config is provided as "myLink", then: 4319 * 4320 * - URL links will have the CSS classes: "myLink myLink-url" 4321 * - Email links will have the CSS classes: "myLink myLink-email", and 4322 * - Phone links will have the CSS classes: "myLink myLink-phone" 4323 * - Hashtag links will have the CSS classes: "myLink myLink-hashtag" 4324 * - Mention links will have the CSS classes: "myLink myLink-mention myLink-[type]" 4325 * where [type] is either "instagram", "twitter" or "soundcloud" 4326 */ 4327 this.className = ''; // default value just to get the above doc comment in the ES5 output and documentation generator 4328 /** 4329 * @cfg {Function} replaceFn 4330 * 4331 * A function to individually process each match found in the input string. 4332 * 4333 * See the class's description for usage. 4334 * 4335 * The `replaceFn` can be called with a different context object (`this` 4336 * reference) using the {@link #context} cfg. 4337 * 4338 * This function is called with the following parameter: 4339 * 4340 * @cfg {Autolinker.match.Match} replaceFn.match The Match instance which 4341 * can be used to retrieve information about the match that the `replaceFn` 4342 * is currently processing. See {@link Autolinker.match.Match} subclasses 4343 * for details. 4344 */ 4345 this.replaceFn = null; // default value just to get the above doc comment in the ES5 output and documentation generator 4346 /** 4347 * @cfg {Object} context 4348 * 4349 * The context object (`this` reference) to call the `replaceFn` with. 4350 * 4351 * Defaults to this Autolinker instance. 4352 */ 4353 this.context = undefined; // default value just to get the above doc comment in the ES5 output and documentation generator 4354 /** 4355 * @cfg {Boolean} [sanitizeHtml=false] 4356 * 4357 * `true` to HTML-encode the start and end brackets of existing HTML tags found 4358 * in the input string. This will escape `<` and `>` characters to `<` and 4359 * `>`, respectively. 4360 * 4361 * Setting this to `true` will prevent XSS (Cross-site Scripting) attacks, 4362 * but will remove the significance of existing HTML tags in the input string. If 4363 * you would like to maintain the significance of existing HTML tags while also 4364 * making the output HTML string safe, leave this option as `false` and use a 4365 * tool like https://github.com/cure53/DOMPurify (or others) on the input string 4366 * before running Autolinker. 4367 */ 4368 this.sanitizeHtml = false; // default value just to get the above doc comment in the ES5 output and documentation generator 4369 /** 4370 * @private 4371 * @property {Autolinker.AnchorTagBuilder} tagBuilder 4372 * 4373 * The AnchorTagBuilder instance used to build match replacement anchor tags. 4374 * Note: this is lazily instantiated in the {@link #getTagBuilder} method. 4375 */ 4376 this.tagBuilder = null; 4377 // Note: when `this.something` is used in the rhs of these assignments, 4378 // it refers to the default values set above the constructor 4379 this.urls = normalizeUrlsCfg(cfg.urls); 4380 this.email = isBoolean(cfg.email) ? cfg.email : this.email; 4381 this.phone = isBoolean(cfg.phone) ? cfg.phone : this.phone; 4382 this.hashtag = cfg.hashtag || this.hashtag; 4383 this.mention = cfg.mention || this.mention; 4384 this.newWindow = isBoolean(cfg.newWindow) ? cfg.newWindow : this.newWindow; 4385 this.stripPrefix = normalizeStripPrefixCfg(cfg.stripPrefix); 4386 this.stripTrailingSlash = isBoolean(cfg.stripTrailingSlash) 4387 ? cfg.stripTrailingSlash 4388 : this.stripTrailingSlash; 4389 this.decodePercentEncoding = isBoolean(cfg.decodePercentEncoding) 4390 ? cfg.decodePercentEncoding 4391 : this.decodePercentEncoding; 4392 this.sanitizeHtml = cfg.sanitizeHtml || false; 4393 // Validate the value of the `mention` cfg 4394 var mention = this.mention; 4395 if (mention !== false && mentionServices.indexOf(mention) === -1) { 4396 throw new Error("invalid `mention` cfg '".concat(mention, "' - see docs")); 4397 } 4398 // Validate the value of the `hashtag` cfg 4399 var hashtag = this.hashtag; 4400 if (hashtag !== false && hashtagServices.indexOf(hashtag) === -1) { 4401 throw new Error("invalid `hashtag` cfg '".concat(hashtag, "' - see docs")); 4402 } 4403 this.truncate = normalizeTruncateCfg(cfg.truncate); 4404 this.className = cfg.className || this.className; 4405 this.replaceFn = cfg.replaceFn || this.replaceFn; 4406 this.context = cfg.context || this; 4407 } 4408 /** 4409 * Automatically links URLs, Email addresses, Phone Numbers, Twitter handles, 4410 * Hashtags, and Mentions found in the given chunk of HTML. Does not link URLs 4411 * found within HTML tags. 4412 * 4413 * For instance, if given the text: `You should go to http://www.yahoo.com`, 4414 * then the result will be `You should go to <a href="http://www.yahoo.com">http://www.yahoo.com</a>` 4415 * 4416 * Example: 4417 * 4418 * var linkedText = Autolinker.link( "Go to google.com", { newWindow: false } ); 4419 * // Produces: "Go to <a href="http://google.com">google.com</a>" 4420 * 4421 * @static 4422 * @param {String} textOrHtml The HTML or text to find matches within (depending 4423 * on if the {@link #urls}, {@link #email}, {@link #phone}, {@link #mention}, 4424 * {@link #hashtag}, and {@link #mention} options are enabled). 4425 * @param {Object} [options] Any of the configuration options for the Autolinker 4426 * class, specified in an Object (map). See the class description for an 4427 * example call. 4428 * @return {String} The HTML text, with matches automatically linked. 4429 */ 4430 Autolinker.link = function (textOrHtml, options) { 4431 var autolinker = new Autolinker(options); 4432 return autolinker.link(textOrHtml); 4433 }; 4434 /** 4435 * Parses the input `textOrHtml` looking for URLs, email addresses, phone 4436 * numbers, username handles, and hashtags (depending on the configuration 4437 * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match} 4438 * objects describing those matches (without making any replacements). 4439 * 4440 * Note that if parsing multiple pieces of text, it is slightly more efficient 4441 * to create an Autolinker instance, and use the instance-level {@link #parse} 4442 * method. 4443 * 4444 * Example: 4445 * 4446 * var matches = Autolinker.parse("Hello google.com, I am [email protected]", { 4447 * urls: true, 4448 * email: true 4449 * }); 4450 * 4451 * console.log(matches.length); // 2 4452 * console.log(matches[0].getType()); // 'url' 4453 * console.log(matches[0].getUrl()); // 'google.com' 4454 * console.log(matches[1].getType()); // 'email' 4455 * console.log(matches[1].getEmail()); // '[email protected]' 4456 * 4457 * @static 4458 * @param {String} textOrHtml The HTML or text to find matches within 4459 * (depending on if the {@link #urls}, {@link #email}, {@link #phone}, 4460 * {@link #hashtag}, and {@link #mention} options are enabled). 4461 * @param {Object} [options] Any of the configuration options for the Autolinker 4462 * class, specified in an Object (map). See the class description for an 4463 * example call. 4464 * @return {Autolinker.match.Match[]} The array of Matches found in the 4465 * given input `textOrHtml`. 4466 */ 4467 Autolinker.parse = function (textOrHtml, options) { 4468 var autolinker = new Autolinker(options); 4469 return autolinker.parse(textOrHtml); 4470 }; 4471 /** 4472 * Parses the input `textOrHtml` looking for URLs, email addresses, phone 4473 * numbers, username handles, and hashtags (depending on the configuration 4474 * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match} 4475 * objects describing those matches (without making any replacements). 4476 * 4477 * This method is used by the {@link #link} method, but can also be used to 4478 * simply do parsing of the input in order to discover what kinds of links 4479 * there are and how many. 4480 * 4481 * Example usage: 4482 * 4483 * var autolinker = new Autolinker( { 4484 * urls: true, 4485 * email: true 4486 * } ); 4487 * 4488 * var matches = autolinker.parse( "Hello google.com, I am [email protected]" ); 4489 * 4490 * console.log( matches.length ); // 2 4491 * console.log( matches[ 0 ].getType() ); // 'url' 4492 * console.log( matches[ 0 ].getUrl() ); // 'google.com' 4493 * console.log( matches[ 1 ].getType() ); // 'email' 4494 * console.log( matches[ 1 ].getEmail() ); // '[email protected]' 4495 * 4496 * @param {String} textOrHtml The HTML or text to find matches within 4497 * (depending on if the {@link #urls}, {@link #email}, {@link #phone}, 4498 * {@link #hashtag}, and {@link #mention} options are enabled). 4499 * @return {Autolinker.match.Match[]} The array of Matches found in the 4500 * given input `textOrHtml`. 4501 */ 4502 Autolinker.prototype.parse = function (textOrHtml) { 4503 var _this = this; 4504 var skipTagNames = ['a', 'style', 'script']; 4505 var skipTagsStackCount = 0; // used to only Autolink text outside of anchor/script/style tags. We don't want to autolink something that is already linked inside of an <a> tag, for instance 4506 var matches = []; 4507 // Find all matches within the `textOrHtml` (but not matches that are 4508 // already nested within <a>, <style> and <script> tags) 4509 parseHtml(textOrHtml, { 4510 onOpenTag: function (tagName) { 4511 if (skipTagNames.indexOf(tagName) >= 0) { 4512 skipTagsStackCount++; 4513 } 4514 }, 4515 onText: function (text, offset) { 4516 // Only process text nodes that are not within an <a>, <style> or <script> tag 4517 if (skipTagsStackCount === 0) { 4518 // "Walk around" common HTML entities. An ' ' (for example) 4519 // could be at the end of a URL, but we don't want to 4520 // include the trailing '&' in the URL. See issue #76 4521 // TODO: Handle HTML entities separately in parseHtml() and 4522 // don't emit them as "text" except for & entities 4523 var htmlCharacterEntitiesRegex = /( | |<|<|>|>|"|"|')/gi; // NOTE: capturing group is significant to include the split characters in the .split() call below 4524 var textSplit = text.split(htmlCharacterEntitiesRegex); 4525 var currentOffset_1 = offset; 4526 textSplit.forEach(function (splitText, i) { 4527 // even number matches are text, odd numbers are html entities 4528 if (i % 2 === 0) { 4529 var textNodeMatches = _this.parseText(splitText, currentOffset_1); 4530 matches.push.apply(matches, __spreadArray([], __read(textNodeMatches), false)); 4531 } 4532 currentOffset_1 += splitText.length; 4533 }); 4534 } 4535 }, 4536 onCloseTag: function (tagName) { 4537 if (skipTagNames.indexOf(tagName) >= 0) { 4538 skipTagsStackCount = Math.max(skipTagsStackCount - 1, 0); // attempt to handle extraneous </a> tags by making sure the stack count never goes below 0 4539 } 4540 }, 4541 onComment: function ( /*_offset: number*/) { }, // no need to process comment nodes 4542 onDoctype: function ( /*_offset: number*/) { }, // no need to process doctype nodes 4543 }); 4544 // After we have found all matches, remove subsequent matches that 4545 // overlap with a previous match. This can happen for instance with an 4546 // email address where the local-part of the email is also a top-level 4547 // domain, such as in "[email protected]". In this case, the entire 4548 // email address should be linked rather than just the 'google.com' 4549 // part. 4550 matches = this.compactMatches(matches); 4551 // And finally, remove matches for match types that have been turned 4552 // off. We needed to have all match types turned on initially so that 4553 // things like hashtags could be filtered out if they were really just 4554 // part of a URL match (for instance, as a named anchor). 4555 matches = this.removeUnwantedMatches(matches); 4556 return matches; 4557 }; 4558 /** 4559 * After we have found all matches, we need to remove matches that overlap 4560 * with a previous match. This can happen for instance with an 4561 * email address where the local-part of the email is also a top-level 4562 * domain, such as in "[email protected]". In this case, the entire email 4563 * address should be linked rather than just the 'google.com' part. 4564 * 4565 * @private 4566 * @param {Autolinker.match.Match[]} matches 4567 * @return {Autolinker.match.Match[]} 4568 */ 4569 Autolinker.prototype.compactMatches = function (matches) { 4570 // First, the matches need to be sorted in order of offset in the input 4571 // string 4572 matches.sort(byMatchOffset); 4573 var i = 0; 4574 while (i < matches.length - 1) { 4575 var match = matches[i]; 4576 var offset = match.getOffset(); 4577 var matchedTextLength = match.getMatchedText().length; 4578 if (i + 1 < matches.length) { 4579 // Remove subsequent matches that equal offset with current match 4580 // This can happen when matching the text "[email protected]" 4581 // where we have both a URL ('google.com') and an email. We 4582 // should only keep the email match in this case. 4583 if (matches[i + 1].getOffset() === offset) { 4584 // Remove the shorter match 4585 var removeIdx = matches[i + 1].getMatchedText().length > matchedTextLength ? i : i + 1; 4586 matches.splice(removeIdx, 1); 4587 continue; 4588 } 4589 // Remove subsequent matches that overlap with the current match 4590 // 4591 // NOTE: This was a fundamental snippet of the Autolinker.js v3 4592 // algorithm where we had multiple regular expressions searching 4593 // the input string for matches. The regexes would sometimes 4594 // overlap such as in the case of "google.com/#link", where we 4595 // would have both a URL match and a hashtag match. 4596 // 4597 // However, the Autolinker.js v4 algorithm uses a state machine 4598 // parser and knows that the '#link' part of 'google.com/#link' 4599 // is part of the URL that precedes it, so we don't need this 4600 // piece of code any more. Keeping it here commented for now in 4601 // case we need to put it back at some point, but none of the 4602 // test cases are currently able to trigger the need for it. 4603 // const endIdx = offset + matchedTextLength; 4604 // if (matches[i + 1].getOffset() < endIdx) { 4605 // matches.splice(i + 1, 1); 4606 // continue; 4607 // } 4608 } 4609 i++; 4610 } 4611 return matches; 4612 }; 4613 /** 4614 * Removes matches for matchers that were turned off in the options. For 4615 * example, if {@link #hashtag hashtags} were not to be matched, we'll 4616 * remove them from the `matches` array here. 4617 * 4618 * Note: we *must* use all Matchers on the input string, and then filter 4619 * them out later. For example, if the options were `{ url: false, hashtag: true }`, 4620 * we wouldn't want to match the text '#link' as a HashTag inside of the text 4621 * 'google.com/#link'. The way the algorithm works is that we match the full 4622 * URL first (which prevents the accidental HashTag match), and then we'll 4623 * simply throw away the URL match. 4624 * 4625 * @private 4626 * @param {Autolinker.match.Match[]} matches The array of matches to remove 4627 * the unwanted matches from. Note: this array is mutated for the 4628 * removals. 4629 * @return {Autolinker.match.Match[]} The mutated input `matches` array. 4630 */ 4631 Autolinker.prototype.removeUnwantedMatches = function (matches) { 4632 if (!this.hashtag) 4633 removeWithPredicate(matches, function (match) { 4634 return match.getType() === 'hashtag'; 4635 }); 4636 if (!this.email) 4637 removeWithPredicate(matches, function (match) { 4638 return match.getType() === 'email'; 4639 }); 4640 if (!this.phone) 4641 removeWithPredicate(matches, function (match) { 4642 return match.getType() === 'phone'; 4643 }); 4644 if (!this.mention) 4645 removeWithPredicate(matches, function (match) { 4646 return match.getType() === 'mention'; 4647 }); 4648 if (!this.urls.schemeMatches) { 4649 removeWithPredicate(matches, function (m) { 4650 return m.getType() === 'url' && m.getUrlMatchType() === 'scheme'; 4651 }); 4652 } 4653 if (!this.urls.tldMatches) { 4654 removeWithPredicate(matches, function (m) { return m.getType() === 'url' && m.getUrlMatchType() === 'tld'; }); 4655 } 4656 if (!this.urls.ipV4Matches) { 4657 removeWithPredicate(matches, function (m) { return m.getType() === 'url' && m.getUrlMatchType() === 'ipV4'; }); 4658 } 4659 return matches; 4660 }; 4661 /** 4662 * Parses the input `text` looking for URLs, email addresses, phone 4663 * numbers, username handles, and hashtags (depending on the configuration 4664 * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match} 4665 * objects describing those matches. 4666 * 4667 * This method processes a **non-HTML string**, and is used to parse and 4668 * match within the text nodes of an HTML string. This method is used 4669 * internally by {@link #parse}. 4670 * 4671 * @private 4672 * @param {String} text The text to find matches within (depending on if the 4673 * {@link #urls}, {@link #email}, {@link #phone}, 4674 * {@link #hashtag}, and {@link #mention} options are enabled). This must be a non-HTML string. 4675 * @param {Number} [offset=0] The offset of the text node within the 4676 * original string. This is used when parsing with the {@link #parse} 4677 * method to generate correct offsets within the {@link Autolinker.match.Match} 4678 * instances, but may be omitted if calling this method publicly. 4679 * @return {Autolinker.match.Match[]} The array of Matches found in the 4680 * given input `text`. 4681 */ 4682 Autolinker.prototype.parseText = function (text, offset) { 4683 offset = offset || 0; 4684 var matches = parseMatches(text, { 4685 tagBuilder: this.getTagBuilder(), 4686 stripPrefix: this.stripPrefix, 4687 stripTrailingSlash: this.stripTrailingSlash, 4688 decodePercentEncoding: this.decodePercentEncoding, 4689 hashtagServiceName: this.hashtag, 4690 mentionServiceName: this.mention || 'twitter', 4691 }); 4692 // Correct the offset of each of the matches. They are originally 4693 // the offset of the match within the provided text node, but we 4694 // need to correct them to be relative to the original HTML input 4695 // string (i.e. the one provided to #parse). 4696 for (var i = 0, numTextMatches = matches.length; i < numTextMatches; i++) { 4697 matches[i].setOffset(offset + matches[i].getOffset()); 4698 } 4699 return matches; 4700 }; 4701 /** 4702 * Automatically links URLs, Email addresses, Phone numbers, Hashtags, 4703 * and Mentions (Twitter, Instagram, Soundcloud) found in the given chunk of HTML. Does not link 4704 * URLs found within HTML tags. 4705 * 4706 * For instance, if given the text: `You should go to http://www.yahoo.com`, 4707 * then the result will be `You should go to 4708 * <a href="http://www.yahoo.com">http://www.yahoo.com</a>` 4709 * 4710 * This method finds the text around any HTML elements in the input 4711 * `textOrHtml`, which will be the text that is processed. Any original HTML 4712 * elements will be left as-is, as well as the text that is already wrapped 4713 * in anchor (<a>) tags. 4714 * 4715 * @param {String} textOrHtml The HTML or text to autolink matches within 4716 * (depending on if the {@link #urls}, {@link #email}, {@link #phone}, {@link #hashtag}, and {@link #mention} options are enabled). 4717 * @return {String} The HTML, with matches automatically linked. 4718 */ 4719 Autolinker.prototype.link = function (textOrHtml) { 4720 if (!textOrHtml) { 4721 return ''; 4722 } // handle `null` and `undefined` (for JavaScript users that don't have TypeScript support), and nothing to do with an empty string too 4723 /* We would want to sanitize the start and end characters of a tag 4724 * before processing the string in order to avoid an XSS scenario. 4725 * This behaviour can be changed by toggling the sanitizeHtml option. 4726 */ 4727 if (this.sanitizeHtml) { 4728 textOrHtml = textOrHtml.replace(/</g, '<').replace(/>/g, '>'); 4729 } 4730 var matches = this.parse(textOrHtml); 4731 var newHtml = new Array(matches.length * 2 + 1); 4732 var lastIndex = 0; 4733 for (var i = 0, len = matches.length; i < len; i++) { 4734 var match = matches[i]; 4735 newHtml.push(textOrHtml.substring(lastIndex, match.getOffset())); 4736 newHtml.push(this.createMatchReturnVal(match)); 4737 lastIndex = match.getOffset() + match.getMatchedText().length; 4738 } 4739 newHtml.push(textOrHtml.substring(lastIndex)); // handle the text after the last match 4740 return newHtml.join(''); 4741 }; 4742 /** 4743 * Creates the return string value for a given match in the input string. 4744 * 4745 * This method handles the {@link #replaceFn}, if one was provided. 4746 * 4747 * @private 4748 * @param {Autolinker.match.Match} match The Match object that represents 4749 * the match. 4750 * @return {String} The string that the `match` should be replaced with. 4751 * This is usually the anchor tag string, but may be the `matchStr` itself 4752 * if the match is not to be replaced. 4753 */ 4754 Autolinker.prototype.createMatchReturnVal = function (match) { 4755 // Handle a custom `replaceFn` being provided 4756 var replaceFnResult; 4757 if (this.replaceFn) { 4758 replaceFnResult = this.replaceFn.call(this.context, match); // Autolinker instance is the context 4759 } 4760 if (typeof replaceFnResult === 'string') { 4761 return replaceFnResult; // `replaceFn` returned a string, use that 4762 } 4763 else if (replaceFnResult === false) { 4764 return match.getMatchedText(); // no replacement for the match 4765 } 4766 else if (replaceFnResult instanceof HtmlTag) { 4767 return replaceFnResult.toAnchorString(); 4768 } 4769 else { 4770 // replaceFnResult === true, or no/unknown return value from function 4771 // Perform Autolinker's default anchor tag generation 4772 var anchorTag = match.buildTag(); // returns an Autolinker.HtmlTag instance 4773 return anchorTag.toAnchorString(); 4774 } 4775 }; 4776 /** 4777 * Returns the {@link #tagBuilder} instance for this Autolinker instance, 4778 * lazily instantiating it if it does not yet exist. 4779 * 4780 * @private 4781 * @return {Autolinker.AnchorTagBuilder} 4782 */ 4783 Autolinker.prototype.getTagBuilder = function () { 4784 var tagBuilder = this.tagBuilder; 4785 if (!tagBuilder) { 4786 tagBuilder = this.tagBuilder = new AnchorTagBuilder({ 4787 newWindow: this.newWindow, 4788 truncate: this.truncate, 4789 className: this.className, 4790 }); 4791 } 4792 return tagBuilder; 4793 }; 4794 // NOTE: must be 'export default' here for UMD module 4795 /** 4796 * @static 4797 * @property {String} version 4798 * 4799 * The Autolinker version number in the form major.minor.patch 4800 * 4801 * Ex: 3.15.0 4802 */ 4803 Autolinker.version = version; 4804 return Autolinker; 4805}());
4806/** 4807 * Normalizes the {@link #urls} config into an Object with its 2 properties: 4808 * `schemeMatches` and `tldMatches`, both booleans. 4809 * 4810 * See {@link #urls} config for details. 4811 * 4812 * @private 4813 * @param {Boolean/Object} urls 4814 * @return {Object} 4815 */ 4816function normalizeUrlsCfg(urls) { 4817 if (urls == null) 4818 urls = true; // default to `true` 4819 if (isBoolean(urls)) { 4820 return { schemeMatches: urls, tldMatches: urls, ipV4Matches: urls }; 4821 } 4822 else { 4823 // object form 4824 return { 4825 schemeMatches: isBoolean(urls.schemeMatches) ? urls.schemeMatches : true, 4826 tldMatches: isBoolean(urls.tldMatches) ? urls.tldMatches : true, 4827 ipV4Matches: isBoolean(urls.ipV4Matches) ? urls.ipV4Matches : true, 4828 }; 4829 } 4830} 4831/** 4832 * Normalizes the {@link #stripPrefix} config into an Object with 2 4833 * properties: `scheme`, and `www` - both Booleans. 4834 * 4835 * See {@link #stripPrefix} config for details. 4836 * 4837 * @private 4838 * @param {Boolean/Object} stripPrefix 4839 * @return {Object} 4840 */ 4841function normalizeStripPrefixCfg(stripPrefix) { 4842 if (stripPrefix == null) 4843 stripPrefix = true; // default to `true` 4844 if (isBoolean(stripPrefix)) { 4845 return { scheme: stripPrefix, www: stripPrefix }; 4846 } 4847 else { 4848 // object form 4849 return { 4850 scheme: isBoolean(stripPrefix.scheme) ? stripPrefix.scheme : true, 4851 www: isBoolean(stripPrefix.www) ? stripPrefix.www : true, 4852 }; 4853 } 4854} 4855/** 4856 * Normalizes the {@link #truncate} config into an Object with 2 properties: 4857 * `length` (Number), and `location` (String). 4858 * 4859 * See {@link #truncate} config for details. 4860 * 4861 * @private 4862 * @param {Number/Object} truncate 4863 * @return {Object} 4864 */ 4865function normalizeTruncateCfg(truncate) { 4866 if (typeof truncate === 'number') { 4867 return { length: truncate, location: 'end' }; 4868 } 4869 else { 4870 // object, or undefined/null 4871 return __assign({ length: Number.POSITIVE_INFINITY, location: 'end' }, truncate); 4872 } 4873} 4874/** 4875 * Helper function for Array.prototype.sort() to sort the Matches by 4876 * their offset in the input string. 4877 */ 4878function byMatchOffset(a, b) { 4879 return a.getOffset() - b.getOffset(); 4880} 4881 4882export { Autolinker as A, __decorate as _, __metadata as a, __param as b }; 4883//# sourceMappingURL=autolinker-aZsZGYsK.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.