tutanota/libs/linkify-html.js

1005 lines
34 KiB
JavaScript
Raw Normal View History

2023-12-13 11:23:54 +01:00
import { Options, tokenize as tokenize$1 } from 'linkifyjs';
2021-05-28 16:46:29 +02:00
/**
* generated from https://raw.githubusercontent.com/w3c/html/26b5126f96f736f796b9e29718138919dd513744/entities.json
* do not edit
*/
var HTML5NamedCharRefs = {
// We don't need the complete named character reference because linkifyHtml
// does not modify the escape sequences. We do need   so that
// whitespace is parsed properly. Other types of whitespace should already
2023-12-13 11:23:54 +01:00
// be accounted for. > < and " are also frequently relevant ones
amp: "&",
gt: ">",
lt: "<",
nbsp: " ",
quot: "\""
2021-05-28 16:46:29 +02:00
};
var HEXCHARCODE = /^#[xX]([A-Fa-f0-9]+)$/;
var CHARCODE = /^#([0-9]+)$/;
var NAMED = /^([A-Za-z0-9]+)$/;
2023-12-13 11:23:54 +01:00
var EntityParser = /** @class */function () {
2021-05-28 16:46:29 +02:00
function EntityParser(named) {
this.named = named;
}
EntityParser.prototype.parse = function (entity) {
if (!entity) {
return;
}
var matches = entity.match(HEXCHARCODE);
if (matches) {
2023-12-13 11:23:54 +01:00
return String.fromCharCode(parseInt(matches[1], 16));
2021-05-28 16:46:29 +02:00
}
matches = entity.match(CHARCODE);
if (matches) {
2023-12-13 11:23:54 +01:00
return String.fromCharCode(parseInt(matches[1], 10));
2021-05-28 16:46:29 +02:00
}
matches = entity.match(NAMED);
if (matches) {
return this.named[matches[1]] || "&" + matches[1] + ";";
}
};
return EntityParser;
}();
var WSP = /[\t\n\f ]/;
var ALPHA = /[A-Za-z]/;
var CRLF = /\r\n?/g;
function isSpace(char) {
return WSP.test(char);
}
function isAlpha(char) {
return ALPHA.test(char);
}
function preprocessInput(input) {
return input.replace(CRLF, '\n');
}
2023-12-13 11:23:54 +01:00
var EventedTokenizer = /** @class */function () {
2021-05-28 16:46:29 +02:00
function EventedTokenizer(delegate, entityParser, mode) {
if (mode === void 0) {
mode = 'precompile';
}
this.delegate = delegate;
this.entityParser = entityParser;
this.mode = mode;
2023-12-13 11:23:54 +01:00
this.state = "beforeData" /* beforeData */;
2021-05-28 16:46:29 +02:00
this.line = -1;
this.column = -1;
this.input = '';
this.index = -1;
this.tagNameBuffer = '';
this.states = {
2023-12-13 11:23:54 +01:00
beforeData: function () {
2021-05-28 16:46:29 +02:00
var char = this.peek();
if (char === '<' && !this.isIgnoredEndTag()) {
2023-12-13 11:23:54 +01:00
this.transitionTo("tagOpen" /* tagOpen */);
2021-05-28 16:46:29 +02:00
this.markTagStart();
this.consume();
} else {
if (this.mode === 'precompile' && char === '\n') {
var tag = this.tagNameBuffer.toLowerCase();
if (tag === 'pre' || tag === 'textarea') {
this.consume();
}
}
2023-12-13 11:23:54 +01:00
this.transitionTo("data" /* data */);
2021-05-28 16:46:29 +02:00
this.delegate.beginData();
}
},
2023-12-13 11:23:54 +01:00
data: function () {
2021-05-28 16:46:29 +02:00
var char = this.peek();
var tag = this.tagNameBuffer;
if (char === '<' && !this.isIgnoredEndTag()) {
this.delegate.finishData();
2023-12-13 11:23:54 +01:00
this.transitionTo("tagOpen" /* tagOpen */);
2021-05-28 16:46:29 +02:00
this.markTagStart();
this.consume();
} else if (char === '&' && tag !== 'script' && tag !== 'style') {
this.consume();
this.delegate.appendToData(this.consumeCharRef() || '&');
} else {
this.consume();
this.delegate.appendToData(char);
}
},
2023-12-13 11:23:54 +01:00
tagOpen: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (char === '!') {
2023-12-13 11:23:54 +01:00
this.transitionTo("markupDeclarationOpen" /* markupDeclarationOpen */);
2021-05-28 16:46:29 +02:00
} else if (char === '/') {
2023-12-13 11:23:54 +01:00
this.transitionTo("endTagOpen" /* endTagOpen */);
2021-05-28 16:46:29 +02:00
} else if (char === '@' || char === ':' || isAlpha(char)) {
2023-12-13 11:23:54 +01:00
this.transitionTo("tagName" /* tagName */);
2021-05-28 16:46:29 +02:00
this.tagNameBuffer = '';
this.delegate.beginStartTag();
this.appendToTagName(char);
}
},
2023-12-13 11:23:54 +01:00
markupDeclarationOpen: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (char === '-' && this.peek() === '-') {
this.consume();
2023-12-13 11:23:54 +01:00
this.transitionTo("commentStart" /* commentStart */);
2021-05-28 16:46:29 +02:00
this.delegate.beginComment();
} else {
var maybeDoctype = char.toUpperCase() + this.input.substring(this.index, this.index + 6).toUpperCase();
if (maybeDoctype === 'DOCTYPE') {
this.consume();
this.consume();
this.consume();
this.consume();
this.consume();
this.consume();
2023-12-13 11:23:54 +01:00
this.transitionTo("doctype" /* doctype */);
2021-05-28 16:46:29 +02:00
if (this.delegate.beginDoctype) this.delegate.beginDoctype();
}
}
},
2023-12-13 11:23:54 +01:00
doctype: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (isSpace(char)) {
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeDoctypeName" /* beforeDoctypeName */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
beforeDoctypeName: function () {
var char = this.consume();
2021-05-28 16:46:29 +02:00
if (isSpace(char)) {
return;
} else {
2023-12-13 11:23:54 +01:00
this.transitionTo("doctypeName" /* doctypeName */);
2021-05-28 16:46:29 +02:00
if (this.delegate.appendToDoctypeName) this.delegate.appendToDoctypeName(char.toLowerCase());
}
},
2023-12-13 11:23:54 +01:00
doctypeName: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (isSpace(char)) {
2023-12-13 11:23:54 +01:00
this.transitionTo("afterDoctypeName" /* afterDoctypeName */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
if (this.delegate.appendToDoctypeName) this.delegate.appendToDoctypeName(char.toLowerCase());
}
},
2023-12-13 11:23:54 +01:00
afterDoctypeName: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (isSpace(char)) {
return;
} else if (char === '>') {
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
var nextSixChars = char.toUpperCase() + this.input.substring(this.index, this.index + 5).toUpperCase();
var isPublic = nextSixChars.toUpperCase() === 'PUBLIC';
var isSystem = nextSixChars.toUpperCase() === 'SYSTEM';
if (isPublic || isSystem) {
this.consume();
this.consume();
this.consume();
this.consume();
this.consume();
this.consume();
}
if (isPublic) {
2023-12-13 11:23:54 +01:00
this.transitionTo("afterDoctypePublicKeyword" /* afterDoctypePublicKeyword */);
2021-05-28 16:46:29 +02:00
} else if (isSystem) {
2023-12-13 11:23:54 +01:00
this.transitionTo("afterDoctypeSystemKeyword" /* afterDoctypeSystemKeyword */);
2021-05-28 16:46:29 +02:00
}
}
},
2023-12-13 11:23:54 +01:00
afterDoctypePublicKeyword: function () {
var char = this.peek();
2021-05-28 16:46:29 +02:00
if (isSpace(char)) {
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeDoctypePublicIdentifier" /* beforeDoctypePublicIdentifier */);
2021-05-28 16:46:29 +02:00
this.consume();
} else if (char === '"') {
2023-12-13 11:23:54 +01:00
this.transitionTo("doctypePublicIdentifierDoubleQuoted" /* doctypePublicIdentifierDoubleQuoted */);
2021-05-28 16:46:29 +02:00
this.consume();
} else if (char === "'") {
2023-12-13 11:23:54 +01:00
this.transitionTo("doctypePublicIdentifierSingleQuoted" /* doctypePublicIdentifierSingleQuoted */);
2021-05-28 16:46:29 +02:00
this.consume();
} else if (char === '>') {
this.consume();
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
doctypePublicIdentifierDoubleQuoted: function () {
var char = this.consume();
2021-05-28 16:46:29 +02:00
if (char === '"') {
2023-12-13 11:23:54 +01:00
this.transitionTo("afterDoctypePublicIdentifier" /* afterDoctypePublicIdentifier */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
if (this.delegate.appendToDoctypePublicIdentifier) this.delegate.appendToDoctypePublicIdentifier(char);
}
},
2023-12-13 11:23:54 +01:00
doctypePublicIdentifierSingleQuoted: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (char === "'") {
2023-12-13 11:23:54 +01:00
this.transitionTo("afterDoctypePublicIdentifier" /* afterDoctypePublicIdentifier */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
if (this.delegate.appendToDoctypePublicIdentifier) this.delegate.appendToDoctypePublicIdentifier(char);
}
},
2023-12-13 11:23:54 +01:00
afterDoctypePublicIdentifier: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (isSpace(char)) {
2023-12-13 11:23:54 +01:00
this.transitionTo("betweenDoctypePublicAndSystemIdentifiers" /* betweenDoctypePublicAndSystemIdentifiers */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else if (char === '"') {
2023-12-13 11:23:54 +01:00
this.transitionTo("doctypeSystemIdentifierDoubleQuoted" /* doctypeSystemIdentifierDoubleQuoted */);
2021-05-28 16:46:29 +02:00
} else if (char === "'") {
2023-12-13 11:23:54 +01:00
this.transitionTo("doctypeSystemIdentifierSingleQuoted" /* doctypeSystemIdentifierSingleQuoted */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
betweenDoctypePublicAndSystemIdentifiers: function () {
var char = this.consume();
2021-05-28 16:46:29 +02:00
if (isSpace(char)) {
return;
} else if (char === '>') {
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else if (char === '"') {
2023-12-13 11:23:54 +01:00
this.transitionTo("doctypeSystemIdentifierDoubleQuoted" /* doctypeSystemIdentifierDoubleQuoted */);
2021-05-28 16:46:29 +02:00
} else if (char === "'") {
2023-12-13 11:23:54 +01:00
this.transitionTo("doctypeSystemIdentifierSingleQuoted" /* doctypeSystemIdentifierSingleQuoted */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
doctypeSystemIdentifierDoubleQuoted: function () {
var char = this.consume();
2021-05-28 16:46:29 +02:00
if (char === '"') {
2023-12-13 11:23:54 +01:00
this.transitionTo("afterDoctypeSystemIdentifier" /* afterDoctypeSystemIdentifier */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
if (this.delegate.appendToDoctypeSystemIdentifier) this.delegate.appendToDoctypeSystemIdentifier(char);
}
},
2023-12-13 11:23:54 +01:00
doctypeSystemIdentifierSingleQuoted: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (char === "'") {
2023-12-13 11:23:54 +01:00
this.transitionTo("afterDoctypeSystemIdentifier" /* afterDoctypeSystemIdentifier */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
if (this.delegate.appendToDoctypeSystemIdentifier) this.delegate.appendToDoctypeSystemIdentifier(char);
}
},
2023-12-13 11:23:54 +01:00
afterDoctypeSystemIdentifier: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (isSpace(char)) {
return;
} else if (char === '>') {
if (this.delegate.endDoctype) this.delegate.endDoctype();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
commentStart: function () {
var char = this.consume();
if (char === '-' && this.peek() === '-') {
2023-12-13 11:23:54 +01:00
this.transitionTo("commentStartDash" /* commentStartDash */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
this.delegate.finishComment();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
this.delegate.appendToCommentData(char);
2023-12-13 11:23:54 +01:00
this.transitionTo("comment" /* comment */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
commentStartDash: function () {
var char = this.consume();
2021-05-28 16:46:29 +02:00
if (char === '-') {
2023-12-13 11:23:54 +01:00
this.transitionTo("commentEnd" /* commentEnd */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
this.delegate.finishComment();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
this.delegate.appendToCommentData('-');
2023-12-13 11:23:54 +01:00
this.transitionTo("comment" /* comment */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
comment: function () {
var char = this.consume();
2021-05-28 16:46:29 +02:00
if (char === '-') {
2023-12-13 11:23:54 +01:00
this.transitionTo("commentEndDash" /* commentEndDash */);
2021-05-28 16:46:29 +02:00
} else {
this.delegate.appendToCommentData(char);
}
},
2023-12-13 11:23:54 +01:00
commentEndDash: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (char === '-' && this.peek() === '-') {
this.delegate.appendToCommentData(char);
} else if (char === '-') {
2023-12-13 11:23:54 +01:00
this.transitionTo("commentEnd" /* commentEnd */);
2021-05-28 16:46:29 +02:00
} else {
this.delegate.appendToCommentData('-' + char);
2023-12-13 11:23:54 +01:00
this.transitionTo("comment" /* comment */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
commentEnd: function () {
var char = this.consume();
2021-05-28 16:46:29 +02:00
if (char === '>') {
this.delegate.finishComment();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
this.delegate.appendToCommentData('--' + char);
2023-12-13 11:23:54 +01:00
this.transitionTo("comment" /* comment */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
tagName: function () {
var char = this.consume();
2021-05-28 16:46:29 +02:00
if (isSpace(char)) {
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeAttributeName" /* beforeAttributeName */);
2021-05-28 16:46:29 +02:00
} else if (char === '/') {
2023-12-13 11:23:54 +01:00
this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
this.delegate.finishTag();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
this.appendToTagName(char);
}
},
2023-12-13 11:23:54 +01:00
endTagName: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (isSpace(char)) {
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeAttributeName" /* beforeAttributeName */);
2021-05-28 16:46:29 +02:00
this.tagNameBuffer = '';
} else if (char === '/') {
2023-12-13 11:23:54 +01:00
this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */);
2021-05-28 16:46:29 +02:00
this.tagNameBuffer = '';
} else if (char === '>') {
this.delegate.finishTag();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
this.tagNameBuffer = '';
} else {
this.appendToTagName(char);
}
},
2023-12-13 11:23:54 +01:00
beforeAttributeName: function () {
2021-05-28 16:46:29 +02:00
var char = this.peek();
if (isSpace(char)) {
this.consume();
return;
} else if (char === '/') {
2023-12-13 11:23:54 +01:00
this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */);
2021-05-28 16:46:29 +02:00
this.consume();
} else if (char === '>') {
this.consume();
this.delegate.finishTag();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else if (char === '=') {
this.delegate.reportSyntaxError('attribute name cannot start with equals sign');
2023-12-13 11:23:54 +01:00
this.transitionTo("attributeName" /* attributeName */);
2021-05-28 16:46:29 +02:00
this.delegate.beginAttribute();
this.consume();
this.delegate.appendToAttributeName(char);
} else {
2023-12-13 11:23:54 +01:00
this.transitionTo("attributeName" /* attributeName */);
2021-05-28 16:46:29 +02:00
this.delegate.beginAttribute();
}
},
2023-12-13 11:23:54 +01:00
attributeName: function () {
2021-05-28 16:46:29 +02:00
var char = this.peek();
if (isSpace(char)) {
2023-12-13 11:23:54 +01:00
this.transitionTo("afterAttributeName" /* afterAttributeName */);
2021-05-28 16:46:29 +02:00
this.consume();
} else if (char === '/') {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
2023-12-13 11:23:54 +01:00
this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */);
2021-05-28 16:46:29 +02:00
} else if (char === '=') {
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeAttributeValue" /* beforeAttributeValue */);
2021-05-28 16:46:29 +02:00
this.consume();
} else if (char === '>') {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
this.delegate.finishTag();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else if (char === '"' || char === "'" || char === '<') {
this.delegate.reportSyntaxError(char + ' is not a valid character within attribute names');
this.consume();
this.delegate.appendToAttributeName(char);
} else {
this.consume();
this.delegate.appendToAttributeName(char);
}
},
2023-12-13 11:23:54 +01:00
afterAttributeName: function () {
2021-05-28 16:46:29 +02:00
var char = this.peek();
if (isSpace(char)) {
this.consume();
return;
} else if (char === '/') {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
2023-12-13 11:23:54 +01:00
this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */);
2021-05-28 16:46:29 +02:00
} else if (char === '=') {
this.consume();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeAttributeValue" /* beforeAttributeValue */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
this.delegate.finishTag();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
2023-12-13 11:23:54 +01:00
this.transitionTo("attributeName" /* attributeName */);
2021-05-28 16:46:29 +02:00
this.delegate.beginAttribute();
this.consume();
this.delegate.appendToAttributeName(char);
}
},
2023-12-13 11:23:54 +01:00
beforeAttributeValue: function () {
2021-05-28 16:46:29 +02:00
var char = this.peek();
if (isSpace(char)) {
this.consume();
} else if (char === '"') {
2023-12-13 11:23:54 +01:00
this.transitionTo("attributeValueDoubleQuoted" /* attributeValueDoubleQuoted */);
2021-05-28 16:46:29 +02:00
this.delegate.beginAttributeValue(true);
this.consume();
} else if (char === "'") {
2023-12-13 11:23:54 +01:00
this.transitionTo("attributeValueSingleQuoted" /* attributeValueSingleQuoted */);
2021-05-28 16:46:29 +02:00
this.delegate.beginAttributeValue(true);
this.consume();
} else if (char === '>') {
this.delegate.beginAttributeValue(false);
this.delegate.finishAttributeValue();
this.consume();
this.delegate.finishTag();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
2023-12-13 11:23:54 +01:00
this.transitionTo("attributeValueUnquoted" /* attributeValueUnquoted */);
2021-05-28 16:46:29 +02:00
this.delegate.beginAttributeValue(false);
this.consume();
this.delegate.appendToAttributeValue(char);
}
},
2023-12-13 11:23:54 +01:00
attributeValueDoubleQuoted: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (char === '"') {
this.delegate.finishAttributeValue();
2023-12-13 11:23:54 +01:00
this.transitionTo("afterAttributeValueQuoted" /* afterAttributeValueQuoted */);
2021-05-28 16:46:29 +02:00
} else if (char === '&') {
this.delegate.appendToAttributeValue(this.consumeCharRef() || '&');
} else {
this.delegate.appendToAttributeValue(char);
}
},
2023-12-13 11:23:54 +01:00
attributeValueSingleQuoted: function () {
2021-05-28 16:46:29 +02:00
var char = this.consume();
if (char === "'") {
this.delegate.finishAttributeValue();
2023-12-13 11:23:54 +01:00
this.transitionTo("afterAttributeValueQuoted" /* afterAttributeValueQuoted */);
2021-05-28 16:46:29 +02:00
} else if (char === '&') {
this.delegate.appendToAttributeValue(this.consumeCharRef() || '&');
} else {
this.delegate.appendToAttributeValue(char);
}
},
2023-12-13 11:23:54 +01:00
attributeValueUnquoted: function () {
2021-05-28 16:46:29 +02:00
var char = this.peek();
if (isSpace(char)) {
this.delegate.finishAttributeValue();
this.consume();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeAttributeName" /* beforeAttributeName */);
2021-05-28 16:46:29 +02:00
} else if (char === '/') {
this.delegate.finishAttributeValue();
this.consume();
2023-12-13 11:23:54 +01:00
this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */);
2021-05-28 16:46:29 +02:00
} else if (char === '&') {
this.consume();
this.delegate.appendToAttributeValue(this.consumeCharRef() || '&');
} else if (char === '>') {
this.delegate.finishAttributeValue();
this.consume();
this.delegate.finishTag();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
this.consume();
this.delegate.appendToAttributeValue(char);
}
},
2023-12-13 11:23:54 +01:00
afterAttributeValueQuoted: function () {
2021-05-28 16:46:29 +02:00
var char = this.peek();
if (isSpace(char)) {
this.consume();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeAttributeName" /* beforeAttributeName */);
2021-05-28 16:46:29 +02:00
} else if (char === '/') {
this.consume();
2023-12-13 11:23:54 +01:00
this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */);
2021-05-28 16:46:29 +02:00
} else if (char === '>') {
this.consume();
this.delegate.finishTag();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeAttributeName" /* beforeAttributeName */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
selfClosingStartTag: function () {
var char = this.peek();
2021-05-28 16:46:29 +02:00
if (char === '>') {
this.consume();
this.delegate.markTagAsSelfClosing();
this.delegate.finishTag();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
} else {
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeAttributeName" /* beforeAttributeName */);
2021-05-28 16:46:29 +02:00
}
},
2023-12-13 11:23:54 +01:00
endTagOpen: function () {
var char = this.consume();
2021-05-28 16:46:29 +02:00
if (char === '@' || char === ':' || isAlpha(char)) {
2023-12-13 11:23:54 +01:00
this.transitionTo("endTagName" /* endTagName */);
2021-05-28 16:46:29 +02:00
this.tagNameBuffer = '';
this.delegate.beginEndTag();
this.appendToTagName(char);
}
}
};
this.reset();
}
EventedTokenizer.prototype.reset = function () {
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
this.input = '';
this.tagNameBuffer = '';
this.index = 0;
this.line = 1;
this.column = 0;
this.delegate.reset();
};
EventedTokenizer.prototype.transitionTo = function (state) {
this.state = state;
};
EventedTokenizer.prototype.tokenize = function (input) {
this.reset();
this.tokenizePart(input);
this.tokenizeEOF();
};
EventedTokenizer.prototype.tokenizePart = function (input) {
this.input += preprocessInput(input);
while (this.index < this.input.length) {
var handler = this.states[this.state];
if (handler !== undefined) {
handler.call(this);
} else {
throw new Error("unhandled state " + this.state);
}
}
};
EventedTokenizer.prototype.tokenizeEOF = function () {
this.flushData();
};
EventedTokenizer.prototype.flushData = function () {
if (this.state === 'data') {
this.delegate.finishData();
2023-12-13 11:23:54 +01:00
this.transitionTo("beforeData" /* beforeData */);
2021-05-28 16:46:29 +02:00
}
};
EventedTokenizer.prototype.peek = function () {
return this.input.charAt(this.index);
};
EventedTokenizer.prototype.consume = function () {
var char = this.peek();
this.index++;
if (char === '\n') {
this.line++;
this.column = 0;
} else {
this.column++;
}
return char;
};
EventedTokenizer.prototype.consumeCharRef = function () {
var endIndex = this.input.indexOf(';', this.index);
if (endIndex === -1) {
return;
}
var entity = this.input.slice(this.index, endIndex);
var chars = this.entityParser.parse(entity);
if (chars) {
2023-12-13 11:23:54 +01:00
var count = entity.length;
// consume the entity chars
2021-05-28 16:46:29 +02:00
while (count) {
this.consume();
count--;
2023-12-13 11:23:54 +01:00
}
// consume the `;`
2021-05-28 16:46:29 +02:00
this.consume();
return chars;
}
};
EventedTokenizer.prototype.markTagStart = function () {
this.delegate.tagOpen();
};
EventedTokenizer.prototype.appendToTagName = function (char) {
this.tagNameBuffer += char;
this.delegate.appendToTagName(char);
};
EventedTokenizer.prototype.isIgnoredEndTag = function () {
var tag = this.tagNameBuffer;
return tag === 'title' && this.input.substring(this.index, this.index + 8) !== '</title>' || tag === 'style' && this.input.substring(this.index, this.index + 8) !== '</style>' || tag === 'script' && this.input.substring(this.index, this.index + 9) !== '</script>';
};
return EventedTokenizer;
}();
2023-12-13 11:23:54 +01:00
var Tokenizer = /** @class */function () {
2021-05-28 16:46:29 +02:00
function Tokenizer(entityParser, options) {
if (options === void 0) {
options = {};
}
this.options = options;
this.token = null;
this.startLine = 1;
this.startColumn = 0;
this.tokens = [];
this.tokenizer = new EventedTokenizer(this, entityParser, options.mode);
this._currentAttribute = undefined;
}
Tokenizer.prototype.tokenize = function (input) {
this.tokens = [];
this.tokenizer.tokenize(input);
return this.tokens;
};
Tokenizer.prototype.tokenizePart = function (input) {
this.tokens = [];
this.tokenizer.tokenizePart(input);
return this.tokens;
};
Tokenizer.prototype.tokenizeEOF = function () {
this.tokens = [];
this.tokenizer.tokenizeEOF();
return this.tokens[0];
};
Tokenizer.prototype.reset = function () {
this.token = null;
this.startLine = 1;
this.startColumn = 0;
};
Tokenizer.prototype.current = function () {
var token = this.token;
if (token === null) {
throw new Error('token was unexpectedly null');
}
if (arguments.length === 0) {
return token;
}
for (var i = 0; i < arguments.length; i++) {
if (token.type === arguments[i]) {
return token;
}
}
throw new Error("token type was unexpectedly " + token.type);
};
Tokenizer.prototype.push = function (token) {
this.token = token;
this.tokens.push(token);
};
Tokenizer.prototype.currentAttribute = function () {
return this._currentAttribute;
};
Tokenizer.prototype.addLocInfo = function () {
if (this.options.loc) {
this.current().loc = {
start: {
line: this.startLine,
column: this.startColumn
},
end: {
line: this.tokenizer.line,
column: this.tokenizer.column
}
};
}
this.startLine = this.tokenizer.line;
this.startColumn = this.tokenizer.column;
2023-12-13 11:23:54 +01:00
};
// Data
2021-05-28 16:46:29 +02:00
Tokenizer.prototype.beginDoctype = function () {
this.push({
2023-12-13 11:23:54 +01:00
type: "Doctype" /* Doctype */,
2021-05-28 16:46:29 +02:00
name: ''
});
};
Tokenizer.prototype.appendToDoctypeName = function (char) {
2023-12-13 11:23:54 +01:00
this.current("Doctype" /* Doctype */).name += char;
2021-05-28 16:46:29 +02:00
};
Tokenizer.prototype.appendToDoctypePublicIdentifier = function (char) {
2023-12-13 11:23:54 +01:00
var doctype = this.current("Doctype" /* Doctype */);
2021-05-28 16:46:29 +02:00
if (doctype.publicIdentifier === undefined) {
doctype.publicIdentifier = char;
} else {
doctype.publicIdentifier += char;
}
};
Tokenizer.prototype.appendToDoctypeSystemIdentifier = function (char) {
2023-12-13 11:23:54 +01:00
var doctype = this.current("Doctype" /* Doctype */);
2021-05-28 16:46:29 +02:00
if (doctype.systemIdentifier === undefined) {
doctype.systemIdentifier = char;
} else {
doctype.systemIdentifier += char;
}
};
Tokenizer.prototype.endDoctype = function () {
this.addLocInfo();
};
Tokenizer.prototype.beginData = function () {
this.push({
2023-12-13 11:23:54 +01:00
type: "Chars" /* Chars */,
2021-05-28 16:46:29 +02:00
chars: ''
});
};
Tokenizer.prototype.appendToData = function (char) {
2023-12-13 11:23:54 +01:00
this.current("Chars" /* Chars */).chars += char;
2021-05-28 16:46:29 +02:00
};
Tokenizer.prototype.finishData = function () {
this.addLocInfo();
2023-12-13 11:23:54 +01:00
};
// Comment
2021-05-28 16:46:29 +02:00
Tokenizer.prototype.beginComment = function () {
this.push({
2023-12-13 11:23:54 +01:00
type: "Comment" /* Comment */,
2021-05-28 16:46:29 +02:00
chars: ''
});
};
Tokenizer.prototype.appendToCommentData = function (char) {
2023-12-13 11:23:54 +01:00
this.current("Comment" /* Comment */).chars += char;
2021-05-28 16:46:29 +02:00
};
Tokenizer.prototype.finishComment = function () {
this.addLocInfo();
2023-12-13 11:23:54 +01:00
};
// Tags - basic
2021-05-28 16:46:29 +02:00
Tokenizer.prototype.tagOpen = function () {};
Tokenizer.prototype.beginStartTag = function () {
this.push({
2023-12-13 11:23:54 +01:00
type: "StartTag" /* StartTag */,
2021-05-28 16:46:29 +02:00
tagName: '',
attributes: [],
selfClosing: false
});
};
Tokenizer.prototype.beginEndTag = function () {
this.push({
2023-12-13 11:23:54 +01:00
type: "EndTag" /* EndTag */,
2021-05-28 16:46:29 +02:00
tagName: ''
});
};
Tokenizer.prototype.finishTag = function () {
this.addLocInfo();
};
Tokenizer.prototype.markTagAsSelfClosing = function () {
2023-12-13 11:23:54 +01:00
this.current("StartTag" /* StartTag */).selfClosing = true;
};
// Tags - name
2021-05-28 16:46:29 +02:00
Tokenizer.prototype.appendToTagName = function (char) {
2023-12-13 11:23:54 +01:00
this.current("StartTag" /* StartTag */, "EndTag" /* EndTag */).tagName += char;
};
// Tags - attributes
2021-05-28 16:46:29 +02:00
Tokenizer.prototype.beginAttribute = function () {
this._currentAttribute = ['', '', false];
};
Tokenizer.prototype.appendToAttributeName = function (char) {
this.currentAttribute()[0] += char;
};
Tokenizer.prototype.beginAttributeValue = function (isQuoted) {
this.currentAttribute()[2] = isQuoted;
};
Tokenizer.prototype.appendToAttributeValue = function (char) {
this.currentAttribute()[1] += char;
};
Tokenizer.prototype.finishAttributeValue = function () {
2023-12-13 11:23:54 +01:00
this.current("StartTag" /* StartTag */).attributes.push(this._currentAttribute);
2021-05-28 16:46:29 +02:00
};
Tokenizer.prototype.reportSyntaxError = function (message) {
this.current().syntaxError = message;
};
return Tokenizer;
}();
function tokenize(input, options) {
var tokenizer = new Tokenizer(new EntityParser(HTML5NamedCharRefs), options);
return tokenizer.tokenize(input);
}
2023-12-13 11:23:54 +01:00
const LinkifyResult = 'LinkifyResult';
const StartTag = 'StartTag';
const EndTag = 'EndTag';
const Chars = 'Chars';
const Comment = 'Comment';
const Doctype = 'Doctype';
2021-05-28 16:46:29 +02:00
/**
* @param {string} str html string to link
2023-12-13 11:23:54 +01:00
* @param {import('linkifyjs').Opts} [opts] linkify options
2021-05-28 16:46:29 +02:00
* @returns {string} resulting string
*/
function linkifyHtml(str, opts = {}) {
2021-05-28 16:46:29 +02:00
// `tokens` and `token` in this section refer to tokens generated by the
// HTML parser, not linkify's parser
2023-12-13 11:23:54 +01:00
const tokens = tokenize(str);
const linkifiedTokens = [];
const linkified = [];
const options = new Options(opts, defaultRender);
// Linkify the tokens given by the parser
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i];
2021-05-28 16:46:29 +02:00
if (token.type === StartTag) {
2023-12-13 11:23:54 +01:00
linkifiedTokens.push(token);
2021-05-28 16:46:29 +02:00
2023-12-13 11:23:54 +01:00
// Ignore all the contents of ignored tags
const tagName = token.tagName.toUpperCase();
const isIgnored = tagName === 'A' || options.ignoreTags.indexOf(tagName) >= 0;
2021-05-28 16:46:29 +02:00
if (!isIgnored) {
continue;
}
2023-12-13 11:23:54 +01:00
let preskipLen = linkifiedTokens.length;
2021-05-28 16:46:29 +02:00
skipTagTokens(tagName, tokens, ++i, linkifiedTokens);
i += linkifiedTokens.length - preskipLen - 1;
} else if (token.type !== Chars) {
// Skip this token, it's not important
linkifiedTokens.push(token);
2023-12-13 11:23:54 +01:00
} else {
// Valid text token, linkify it!
const linkifedChars = linkifyChars(token.chars, options);
linkifiedTokens.push.apply(linkifiedTokens, linkifedChars);
}
}
2021-05-28 16:46:29 +02:00
2023-12-13 11:23:54 +01:00
// Convert the tokens back into a string
for (let i = 0; i < linkifiedTokens.length; i++) {
const token = linkifiedTokens[i];
switch (token.type) {
case LinkifyResult:
linkified.push(token.rendered);
break;
2021-05-28 16:46:29 +02:00
case StartTag:
{
2023-12-13 11:23:54 +01:00
let link = '<' + token.tagName;
if (token.attributes.length > 0) {
link += ' ' + attributeArrayToStrings(token.attributes).join(' ');
}
if (token.selfClosing) {
link += ' /';
2021-05-28 16:46:29 +02:00
}
link += '>';
linkified.push(link);
break;
}
case EndTag:
2023-12-13 11:23:54 +01:00
linkified.push(`</${token.tagName}>`);
2021-05-28 16:46:29 +02:00
break;
case Chars:
2023-12-13 11:23:54 +01:00
linkified.push(escapeText(token.chars));
2021-05-28 16:46:29 +02:00
break;
case Comment:
2023-12-13 11:23:54 +01:00
linkified.push(`<!--${escapeText(token.chars)}-->`);
2021-05-28 16:46:29 +02:00
break;
case Doctype:
{
2023-12-13 11:23:54 +01:00
let doctype = `<!DOCTYPE ${token.name}`;
if (token.publicIdentifier) {
doctype += ` PUBLIC "${token.publicIdentifier}"`;
2021-05-28 16:46:29 +02:00
}
2023-12-13 11:23:54 +01:00
if (token.systemIdentifier) {
doctype += ` "${token.systemIdentifier}"`;
2021-05-28 16:46:29 +02:00
}
doctype += '>';
linkified.push(doctype);
break;
}
}
}
return linkified.join('');
}
2023-12-13 11:23:54 +01:00
2021-05-28 16:46:29 +02:00
/**
`tokens` and `token` in this section referes to tokens returned by
`linkify.tokenize`. `linkified` will contain HTML Parser-style tokens
2023-12-13 11:23:54 +01:00
@param {string}
@param {import('linkifyjs').Options}
2021-05-28 16:46:29 +02:00
*/
2023-12-13 11:23:54 +01:00
function linkifyChars(str, options) {
const tokens = tokenize$1(str);
const result = [];
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i];
if (token.t === 'nl' && options.get('nl2br')) {
2021-05-28 16:46:29 +02:00
result.push({
type: StartTag,
tagName: 'br',
attributes: [],
selfClosing: true
});
2023-12-13 11:23:54 +01:00
} else if (!token.isLink || !options.check(token)) {
2021-05-28 16:46:29 +02:00
result.push({
type: Chars,
chars: token.toString()
});
2023-12-13 11:23:54 +01:00
} else {
result.push({
type: LinkifyResult,
rendered: options.render(token)
});
2021-05-28 16:46:29 +02:00
}
}
return result;
}
2023-12-13 11:23:54 +01:00
2021-05-28 16:46:29 +02:00
/**
Returns a list of tokens skipped until the closing tag of tagName.
* `tagName` is the closing tag which will prompt us to stop skipping
* `tokens` is the array of tokens generated by HTML5Tokenizer which
* `i` is the index immediately after the opening tag to skip
* `skippedTokens` is an array which skipped tokens are being pushed into
Caveats
* Assumes that i is the first token after the given opening tagName
* The closing tag will be skipped, but nothing after it
* Will track whether there is a nested tag of the same type
*/
function skipTagTokens(tagName, tokens, i, skippedTokens) {
// number of tokens of this type on the [fictional] stack
2023-12-13 11:23:54 +01:00
let stackCount = 1;
2021-05-28 16:46:29 +02:00
while (i < tokens.length && stackCount > 0) {
2023-12-13 11:23:54 +01:00
let token = tokens[i];
2021-05-28 16:46:29 +02:00
if (token.type === StartTag && token.tagName.toUpperCase() === tagName) {
// Nested tag of the same type, "add to stack"
stackCount++;
} else if (token.type === EndTag && token.tagName.toUpperCase() === tagName) {
// Closing tag
stackCount--;
}
skippedTokens.push(token);
i++;
2023-12-13 11:23:54 +01:00
}
2021-05-28 16:46:29 +02:00
2023-12-13 11:23:54 +01:00
// Note that if stackCount > 0 here, the HTML is probably invalid
2021-05-28 16:46:29 +02:00
return skippedTokens;
}
function defaultRender({
tagName,
attributes,
content
}) {
2023-12-13 11:23:54 +01:00
return `<${tagName} ${attributesToString(attributes)}>${escapeText(content)}</${tagName}>`;
}
2021-05-28 16:46:29 +02:00
function escapeText(text) {
2023-12-13 11:23:54 +01:00
return text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
2021-05-28 16:46:29 +02:00
}
function escapeAttr(attr) {
return attr.replace(/"/g, '&quot;');
}
2023-12-13 11:23:54 +01:00
function attributesToString(attributes) {
const result = [];
for (const attr in attributes) {
const val = attributes[attr] + '';
result.push(`${attr}="${escapeAttr(val)}"`);
}
return result.join(' ');
}
function attributeArrayToStrings(attrs) {
const attrStrs = [];
for (let i = 0; i < attrs.length; i++) {
const name = attrs[i][0];
const value = attrs[i][1] + '';
attrStrs.push(`${name}="${escapeAttr(value)}"`);
2021-05-28 16:46:29 +02:00
}
return attrStrs;
}
2022-01-19 15:17:38 +01:00
export { linkifyHtml as default };