'use strict'; var linkify = require('linkifyjs'); function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var linkify__namespace = /*#__PURE__*/_interopNamespace(linkify); /** * 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 // be accounted for nbsp: " " }; var HEXCHARCODE = /^#[xX]([A-Fa-f0-9]+)$/; var CHARCODE = /^#([0-9]+)$/; var NAMED = /^([A-Za-z0-9]+)$/; var EntityParser = /** @class */ function () { function EntityParser(named) { this.named = named; } EntityParser.prototype.parse = function (entity) { if (!entity) { return; } var matches = entity.match(HEXCHARCODE); if (matches) { return "&#x" + matches[1] + ";"; } matches = entity.match(CHARCODE); if (matches) { return "&#" + matches[1] + ";"; } 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'); } var EventedTokenizer = /** @class */ function () { function EventedTokenizer(delegate, entityParser, mode) { if (mode === void 0) { mode = 'precompile'; } this.delegate = delegate; this.entityParser = entityParser; this.mode = mode; this.state = "beforeData" /* beforeData */ ; this.line = -1; this.column = -1; this.input = ''; this.index = -1; this.tagNameBuffer = ''; this.states = { beforeData: function beforeData() { var char = this.peek(); if (char === '<' && !this.isIgnoredEndTag()) { this.transitionTo("tagOpen" /* tagOpen */ ); this.markTagStart(); this.consume(); } else { if (this.mode === 'precompile' && char === '\n') { var tag = this.tagNameBuffer.toLowerCase(); if (tag === 'pre' || tag === 'textarea') { this.consume(); } } this.transitionTo("data" /* data */ ); this.delegate.beginData(); } }, data: function data() { var char = this.peek(); var tag = this.tagNameBuffer; if (char === '<' && !this.isIgnoredEndTag()) { this.delegate.finishData(); this.transitionTo("tagOpen" /* tagOpen */ ); 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); } }, tagOpen: function tagOpen() { var char = this.consume(); if (char === '!') { this.transitionTo("markupDeclarationOpen" /* markupDeclarationOpen */ ); } else if (char === '/') { this.transitionTo("endTagOpen" /* endTagOpen */ ); } else if (char === '@' || char === ':' || isAlpha(char)) { this.transitionTo("tagName" /* tagName */ ); this.tagNameBuffer = ''; this.delegate.beginStartTag(); this.appendToTagName(char); } }, markupDeclarationOpen: function markupDeclarationOpen() { var char = this.consume(); if (char === '-' && this.peek() === '-') { this.consume(); this.transitionTo("commentStart" /* commentStart */ ); 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(); this.transitionTo("doctype" /* doctype */ ); if (this.delegate.beginDoctype) this.delegate.beginDoctype(); } } }, doctype: function doctype() { var char = this.consume(); if (isSpace(char)) { this.transitionTo("beforeDoctypeName" /* beforeDoctypeName */ ); } }, beforeDoctypeName: function beforeDoctypeName() { var char = this.consume(); if (isSpace(char)) { return; } else { this.transitionTo("doctypeName" /* doctypeName */ ); if (this.delegate.appendToDoctypeName) this.delegate.appendToDoctypeName(char.toLowerCase()); } }, doctypeName: function doctypeName() { var char = this.consume(); if (isSpace(char)) { this.transitionTo("afterDoctypeName" /* afterDoctypeName */ ); } else if (char === '>') { if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } else { if (this.delegate.appendToDoctypeName) this.delegate.appendToDoctypeName(char.toLowerCase()); } }, afterDoctypeName: function afterDoctypeName() { var char = this.consume(); if (isSpace(char)) { return; } else if (char === '>') { if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } 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) { this.transitionTo("afterDoctypePublicKeyword" /* afterDoctypePublicKeyword */ ); } else if (isSystem) { this.transitionTo("afterDoctypeSystemKeyword" /* afterDoctypeSystemKeyword */ ); } } }, afterDoctypePublicKeyword: function afterDoctypePublicKeyword() { var char = this.peek(); if (isSpace(char)) { this.transitionTo("beforeDoctypePublicIdentifier" /* beforeDoctypePublicIdentifier */ ); this.consume(); } else if (char === '"') { this.transitionTo("doctypePublicIdentifierDoubleQuoted" /* doctypePublicIdentifierDoubleQuoted */ ); this.consume(); } else if (char === "'") { this.transitionTo("doctypePublicIdentifierSingleQuoted" /* doctypePublicIdentifierSingleQuoted */ ); this.consume(); } else if (char === '>') { this.consume(); if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } }, doctypePublicIdentifierDoubleQuoted: function doctypePublicIdentifierDoubleQuoted() { var char = this.consume(); if (char === '"') { this.transitionTo("afterDoctypePublicIdentifier" /* afterDoctypePublicIdentifier */ ); } else if (char === '>') { if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } else { if (this.delegate.appendToDoctypePublicIdentifier) this.delegate.appendToDoctypePublicIdentifier(char); } }, doctypePublicIdentifierSingleQuoted: function doctypePublicIdentifierSingleQuoted() { var char = this.consume(); if (char === "'") { this.transitionTo("afterDoctypePublicIdentifier" /* afterDoctypePublicIdentifier */ ); } else if (char === '>') { if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } else { if (this.delegate.appendToDoctypePublicIdentifier) this.delegate.appendToDoctypePublicIdentifier(char); } }, afterDoctypePublicIdentifier: function afterDoctypePublicIdentifier() { var char = this.consume(); if (isSpace(char)) { this.transitionTo("betweenDoctypePublicAndSystemIdentifiers" /* betweenDoctypePublicAndSystemIdentifiers */ ); } else if (char === '>') { if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } else if (char === '"') { this.transitionTo("doctypeSystemIdentifierDoubleQuoted" /* doctypeSystemIdentifierDoubleQuoted */ ); } else if (char === "'") { this.transitionTo("doctypeSystemIdentifierSingleQuoted" /* doctypeSystemIdentifierSingleQuoted */ ); } }, betweenDoctypePublicAndSystemIdentifiers: function betweenDoctypePublicAndSystemIdentifiers() { var char = this.consume(); if (isSpace(char)) { return; } else if (char === '>') { if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } else if (char === '"') { this.transitionTo("doctypeSystemIdentifierDoubleQuoted" /* doctypeSystemIdentifierDoubleQuoted */ ); } else if (char === "'") { this.transitionTo("doctypeSystemIdentifierSingleQuoted" /* doctypeSystemIdentifierSingleQuoted */ ); } }, doctypeSystemIdentifierDoubleQuoted: function doctypeSystemIdentifierDoubleQuoted() { var char = this.consume(); if (char === '"') { this.transitionTo("afterDoctypeSystemIdentifier" /* afterDoctypeSystemIdentifier */ ); } else if (char === '>') { if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } else { if (this.delegate.appendToDoctypeSystemIdentifier) this.delegate.appendToDoctypeSystemIdentifier(char); } }, doctypeSystemIdentifierSingleQuoted: function doctypeSystemIdentifierSingleQuoted() { var char = this.consume(); if (char === "'") { this.transitionTo("afterDoctypeSystemIdentifier" /* afterDoctypeSystemIdentifier */ ); } else if (char === '>') { if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } else { if (this.delegate.appendToDoctypeSystemIdentifier) this.delegate.appendToDoctypeSystemIdentifier(char); } }, afterDoctypeSystemIdentifier: function afterDoctypeSystemIdentifier() { var char = this.consume(); if (isSpace(char)) { return; } else if (char === '>') { if (this.delegate.endDoctype) this.delegate.endDoctype(); this.transitionTo("beforeData" /* beforeData */ ); } }, commentStart: function commentStart() { var char = this.consume(); if (char === '-') { this.transitionTo("commentStartDash" /* commentStartDash */ ); } else if (char === '>') { this.delegate.finishComment(); this.transitionTo("beforeData" /* beforeData */ ); } else { this.delegate.appendToCommentData(char); this.transitionTo("comment" /* comment */ ); } }, commentStartDash: function commentStartDash() { var char = this.consume(); if (char === '-') { this.transitionTo("commentEnd" /* commentEnd */ ); } else if (char === '>') { this.delegate.finishComment(); this.transitionTo("beforeData" /* beforeData */ ); } else { this.delegate.appendToCommentData('-'); this.transitionTo("comment" /* comment */ ); } }, comment: function comment() { var char = this.consume(); if (char === '-') { this.transitionTo("commentEndDash" /* commentEndDash */ ); } else { this.delegate.appendToCommentData(char); } }, commentEndDash: function commentEndDash() { var char = this.consume(); if (char === '-') { this.transitionTo("commentEnd" /* commentEnd */ ); } else { this.delegate.appendToCommentData('-' + char); this.transitionTo("comment" /* comment */ ); } }, commentEnd: function commentEnd() { var char = this.consume(); if (char === '>') { this.delegate.finishComment(); this.transitionTo("beforeData" /* beforeData */ ); } else { this.delegate.appendToCommentData('--' + char); this.transitionTo("comment" /* comment */ ); } }, tagName: function tagName() { var char = this.consume(); if (isSpace(char)) { this.transitionTo("beforeAttributeName" /* beforeAttributeName */ ); } else if (char === '/') { this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */ ); } else if (char === '>') { this.delegate.finishTag(); this.transitionTo("beforeData" /* beforeData */ ); } else { this.appendToTagName(char); } }, endTagName: function endTagName() { var char = this.consume(); if (isSpace(char)) { this.transitionTo("beforeAttributeName" /* beforeAttributeName */ ); this.tagNameBuffer = ''; } else if (char === '/') { this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */ ); this.tagNameBuffer = ''; } else if (char === '>') { this.delegate.finishTag(); this.transitionTo("beforeData" /* beforeData */ ); this.tagNameBuffer = ''; } else { this.appendToTagName(char); } }, beforeAttributeName: function beforeAttributeName() { var char = this.peek(); if (isSpace(char)) { this.consume(); return; } else if (char === '/') { this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */ ); this.consume(); } else if (char === '>') { this.consume(); this.delegate.finishTag(); this.transitionTo("beforeData" /* beforeData */ ); } else if (char === '=') { this.delegate.reportSyntaxError('attribute name cannot start with equals sign'); this.transitionTo("attributeName" /* attributeName */ ); this.delegate.beginAttribute(); this.consume(); this.delegate.appendToAttributeName(char); } else { this.transitionTo("attributeName" /* attributeName */ ); this.delegate.beginAttribute(); } }, attributeName: function attributeName() { var char = this.peek(); if (isSpace(char)) { this.transitionTo("afterAttributeName" /* afterAttributeName */ ); this.consume(); } else if (char === '/') { this.delegate.beginAttributeValue(false); this.delegate.finishAttributeValue(); this.consume(); this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */ ); } else if (char === '=') { this.transitionTo("beforeAttributeValue" /* beforeAttributeValue */ ); this.consume(); } else if (char === '>') { this.delegate.beginAttributeValue(false); this.delegate.finishAttributeValue(); this.consume(); this.delegate.finishTag(); this.transitionTo("beforeData" /* beforeData */ ); } 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); } }, afterAttributeName: function afterAttributeName() { var char = this.peek(); if (isSpace(char)) { this.consume(); return; } else if (char === '/') { this.delegate.beginAttributeValue(false); this.delegate.finishAttributeValue(); this.consume(); this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */ ); } else if (char === '=') { this.consume(); this.transitionTo("beforeAttributeValue" /* beforeAttributeValue */ ); } else if (char === '>') { this.delegate.beginAttributeValue(false); this.delegate.finishAttributeValue(); this.consume(); this.delegate.finishTag(); this.transitionTo("beforeData" /* beforeData */ ); } else { this.delegate.beginAttributeValue(false); this.delegate.finishAttributeValue(); this.transitionTo("attributeName" /* attributeName */ ); this.delegate.beginAttribute(); this.consume(); this.delegate.appendToAttributeName(char); } }, beforeAttributeValue: function beforeAttributeValue() { var char = this.peek(); if (isSpace(char)) { this.consume(); } else if (char === '"') { this.transitionTo("attributeValueDoubleQuoted" /* attributeValueDoubleQuoted */ ); this.delegate.beginAttributeValue(true); this.consume(); } else if (char === "'") { this.transitionTo("attributeValueSingleQuoted" /* attributeValueSingleQuoted */ ); this.delegate.beginAttributeValue(true); this.consume(); } else if (char === '>') { this.delegate.beginAttributeValue(false); this.delegate.finishAttributeValue(); this.consume(); this.delegate.finishTag(); this.transitionTo("beforeData" /* beforeData */ ); } else { this.transitionTo("attributeValueUnquoted" /* attributeValueUnquoted */ ); this.delegate.beginAttributeValue(false); this.consume(); this.delegate.appendToAttributeValue(char); } }, attributeValueDoubleQuoted: function attributeValueDoubleQuoted() { var char = this.consume(); if (char === '"') { this.delegate.finishAttributeValue(); this.transitionTo("afterAttributeValueQuoted" /* afterAttributeValueQuoted */ ); } else if (char === '&') { this.delegate.appendToAttributeValue(this.consumeCharRef() || '&'); } else { this.delegate.appendToAttributeValue(char); } }, attributeValueSingleQuoted: function attributeValueSingleQuoted() { var char = this.consume(); if (char === "'") { this.delegate.finishAttributeValue(); this.transitionTo("afterAttributeValueQuoted" /* afterAttributeValueQuoted */ ); } else if (char === '&') { this.delegate.appendToAttributeValue(this.consumeCharRef() || '&'); } else { this.delegate.appendToAttributeValue(char); } }, attributeValueUnquoted: function attributeValueUnquoted() { var char = this.peek(); if (isSpace(char)) { this.delegate.finishAttributeValue(); this.consume(); this.transitionTo("beforeAttributeName" /* beforeAttributeName */ ); } else if (char === '/') { this.delegate.finishAttributeValue(); this.consume(); this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */ ); } else if (char === '&') { this.consume(); this.delegate.appendToAttributeValue(this.consumeCharRef() || '&'); } else if (char === '>') { this.delegate.finishAttributeValue(); this.consume(); this.delegate.finishTag(); this.transitionTo("beforeData" /* beforeData */ ); } else { this.consume(); this.delegate.appendToAttributeValue(char); } }, afterAttributeValueQuoted: function afterAttributeValueQuoted() { var char = this.peek(); if (isSpace(char)) { this.consume(); this.transitionTo("beforeAttributeName" /* beforeAttributeName */ ); } else if (char === '/') { this.consume(); this.transitionTo("selfClosingStartTag" /* selfClosingStartTag */ ); } else if (char === '>') { this.consume(); this.delegate.finishTag(); this.transitionTo("beforeData" /* beforeData */ ); } else { this.transitionTo("beforeAttributeName" /* beforeAttributeName */ ); } }, selfClosingStartTag: function selfClosingStartTag() { var char = this.peek(); if (char === '>') { this.consume(); this.delegate.markTagAsSelfClosing(); this.delegate.finishTag(); this.transitionTo("beforeData" /* beforeData */ ); } else { this.transitionTo("beforeAttributeName" /* beforeAttributeName */ ); } }, endTagOpen: function endTagOpen() { var char = this.consume(); if (char === '@' || char === ':' || isAlpha(char)) { this.transitionTo("endTagName" /* endTagName */ ); this.tagNameBuffer = ''; this.delegate.beginEndTag(); this.appendToTagName(char); } } }; this.reset(); } EventedTokenizer.prototype.reset = function () { this.transitionTo("beforeData" /* beforeData */ ); 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(); this.transitionTo("beforeData" /* beforeData */ ); } }; 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) { var count = entity.length; // consume the entity chars while (count) { this.consume(); count--; } // consume the `;` 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) !== '' || tag === 'style' && this.input.substring(this.index, this.index + 8) !== '' || tag === 'script' && this.input.substring(this.index, this.index + 9) !== ''; }; return EventedTokenizer; }(); var Tokenizer = /** @class */ function () { 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; }; // Data Tokenizer.prototype.beginDoctype = function () { this.push({ type: "Doctype" /* Doctype */ , name: '' }); }; Tokenizer.prototype.appendToDoctypeName = function (char) { this.current("Doctype" /* Doctype */ ).name += char; }; Tokenizer.prototype.appendToDoctypePublicIdentifier = function (char) { var doctype = this.current("Doctype" /* Doctype */ ); if (doctype.publicIdentifier === undefined) { doctype.publicIdentifier = char; } else { doctype.publicIdentifier += char; } }; Tokenizer.prototype.appendToDoctypeSystemIdentifier = function (char) { var doctype = this.current("Doctype" /* Doctype */ ); if (doctype.systemIdentifier === undefined) { doctype.systemIdentifier = char; } else { doctype.systemIdentifier += char; } }; Tokenizer.prototype.endDoctype = function () { this.addLocInfo(); }; Tokenizer.prototype.beginData = function () { this.push({ type: "Chars" /* Chars */ , chars: '' }); }; Tokenizer.prototype.appendToData = function (char) { this.current("Chars" /* Chars */ ).chars += char; }; Tokenizer.prototype.finishData = function () { this.addLocInfo(); }; // Comment Tokenizer.prototype.beginComment = function () { this.push({ type: "Comment" /* Comment */ , chars: '' }); }; Tokenizer.prototype.appendToCommentData = function (char) { this.current("Comment" /* Comment */ ).chars += char; }; Tokenizer.prototype.finishComment = function () { this.addLocInfo(); }; // Tags - basic Tokenizer.prototype.tagOpen = function () {}; Tokenizer.prototype.beginStartTag = function () { this.push({ type: "StartTag" /* StartTag */ , tagName: '', attributes: [], selfClosing: false }); }; Tokenizer.prototype.beginEndTag = function () { this.push({ type: "EndTag" /* EndTag */ , tagName: '' }); }; Tokenizer.prototype.finishTag = function () { this.addLocInfo(); }; Tokenizer.prototype.markTagAsSelfClosing = function () { this.current("StartTag" /* StartTag */ ).selfClosing = true; }; // Tags - name Tokenizer.prototype.appendToTagName = function (char) { this.current("StartTag" /* StartTag */ , "EndTag" /* EndTag */ ).tagName += char; }; // Tags - attributes 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 () { this.current("StartTag" /* StartTag */ ).attributes.push(this._currentAttribute); }; 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); } var Options = linkify__namespace.Options; var StartTag = 'StartTag'; var EndTag = 'EndTag'; var Chars = 'Chars'; var Comment = 'Comment'; var Doctype = 'Doctype'; /** * @param {string} str html string to link * @param {object} [opts] linkify options * @returns {string} resulting string */ function linkifyHtml(str) { var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; // `tokens` and `token` in this section refer to tokens generated by the // HTML parser, not linkify's parser var tokens = tokenize(str); var linkifiedTokens = []; var linkified = []; opts = new Options(opts); // Linkify the tokens given by the parser for (var i = 0; i < tokens.length; i++) { var token = tokens[i]; if (token.type === StartTag) { linkifiedTokens.push(token); // Ignore all the contents of ignored tags var tagName = token.tagName.toUpperCase(); var isIgnored = tagName === 'A' || opts.ignoreTags.indexOf(tagName) >= 0; if (!isIgnored) { continue; } var preskipLen = linkifiedTokens.length; skipTagTokens(tagName, tokens, ++i, linkifiedTokens); i += linkifiedTokens.length - preskipLen - 1; continue; } else if (token.type !== Chars) { // Skip this token, it's not important linkifiedTokens.push(token); continue; } // Valid text token, linkify it! var linkifedChars = linkifyChars(token.chars, opts); linkifiedTokens.push.apply(linkifiedTokens, linkifedChars); } // Convert the tokens back into a string for (var _i = 0; _i < linkifiedTokens.length; _i++) { var _token = linkifiedTokens[_i]; switch (_token.type) { case StartTag: { var link = '<' + _token.tagName; if (_token.attributes.length > 0) { var attrs = attrsToStrings(_token.attributes); link += ' ' + attrs.join(' '); } link += '>'; linkified.push(link); break; } case EndTag: linkified.push("")); break; case Chars: linkified.push(escapeText(_token.chars)); break; case Comment: linkified.push("")); break; case Doctype: { var doctype = "'; linkified.push(doctype); break; } } } return linkified.join(''); } /** `tokens` and `token` in this section referes to tokens returned by `linkify.tokenize`. `linkified` will contain HTML Parser-style tokens */ function linkifyChars(str, opts) { var tokens = linkify__namespace.tokenize(str); var result = []; for (var i = 0; i < tokens.length; i++) { var token = tokens[i]; if (token.t === 'nl' && opts.nl2br) { result.push({ type: StartTag, tagName: 'br', attributes: [], selfClosing: true }); continue; } else if (!token.isLink || !opts.check(token)) { result.push({ type: Chars, chars: token.toString() }); continue; } var _opts$resolve = opts.resolve(token), formatted = _opts$resolve.formatted, formattedHref = _opts$resolve.formattedHref, tagName = _opts$resolve.tagName, className = _opts$resolve.className, target = _opts$resolve.target, rel = _opts$resolve.rel, attributes = _opts$resolve.attributes, truncate = _opts$resolve.truncate; // Build up attributes var attributeArray = [['href', formattedHref]]; if (className) { attributeArray.push(['class', className]); } if (target) { attributeArray.push(['target', target]); } if (rel) { attributeArray.push(['rel', rel]); } if (truncate && formatted.length > truncate) { formatted = formatted.substring(0, truncate) + '…'; } for (var attr in attributes) { attributeArray.push([attr, attributes[attr]]); } // Add the required tokens result.push({ type: StartTag, tagName: tagName, attributes: attributeArray, selfClosing: false }); result.push({ type: Chars, chars: formatted }); result.push({ type: EndTag, tagName: tagName }); } return result; } /** 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 var stackCount = 1; while (i < tokens.length && stackCount > 0) { var token = tokens[i]; 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++; } // Note that if stackCount > 0 here, the HTML is probably invalid return skippedTokens; } function escapeText(text) { // Not required, HTML tokenizer ensures this occurs properly return text; } function escapeAttr(attr) { return attr.replace(/"/g, '"'); } function attrsToStrings(attrs) { var attrStrs = []; for (var i = 0; i < attrs.length; i++) { var name = attrs[i][0]; var value = attrs[i][1]; attrStrs.push("".concat(name, "=\"").concat(escapeAttr(value), "\"")); } return attrStrs; } module.exports = linkifyHtml;