/*global global*/ (function markup_init() { "use strict"; const framework:parseFramework = global.parseFramework, markup = function lexer_markup(source:string):data { let a:number = 0, list:number = 0, litag:number = 0, sgmlflag:number = 0, cftransaction:boolean = false, ext:boolean = false; const parse:parse = framework.parse, data:data = parse.data, count:markupCount = { end : 0, index: -1, start: 0 }, options:parseOptions = parse.parseOptions, b:string[] = source.split(""), c:number = b.length, recordPush = function lexer_markup_recordPush(target, record, structure):void { if (target === data) { if (record.types.indexOf("end") > -1) { count.end = count.end + 1; } else if (record.types.indexOf("start") > -1) { count.start = count.start + 1; } } parse.push(target, record, structure); }, // Find the lowercase tag name of the provided token. tagName = function lexer_markup_tagName(el:string):string { let space:number = 0, name:string = ""; const reg:RegExp = (/^(\{((%-?)|\{-?)\s*)/); if (typeof el !== "string") { return ""; } space = el .replace(reg, "%") .replace(/\s+/, " ") .indexOf(" "); name = el.replace(reg, " "); name = (space < 0) ? name.slice(1, el.length - 1) : name.slice(1, space); if (options.language === "html" || options.language === "coldfusion") { name = name.toLowerCase(); } name = name.replace(/(\}\})$/, ""); if (name.indexOf("(") > 0) { name = name.slice(0, name.indexOf("(")); } if (name === "?xml?") { return "xml"; } return name; }, //parses tags, attributes, and template elements tag = function lexer_markup_tag(end:string):void { // markup is two smaller lexers that work together: tag - evaluates markup and // template tags content - evaluates text content and code for external lexers // //type definitions: // * start end type // * cdata // * comment // * <#-- --> comment // * <%-- --%> comment // * {! !} comment // * conditional // * text text content // * > end // *
ignore (html only)
// * text text script
// * sgml
// * < /> singleton
// * < > start
// * text text style
// * template
// * <% %> template
// * {{{ }}} template
// * {{ }} template
// * {% %} template
// * [% %] template
// * {@ @} template
// * {# #} template
// * {# /} template
// * {? /} template
// * {^ /} template
// * {@ /} template
// * {< /} template
// * {+ /} template
// * {~ } template
// * ?> template
// * {:else} template_else
// * <#else > template_else
// * {@}else{@} template_else
// * <%}else{%> template_else
// * {{ }} template_end
// * <%\s*} %> template_end
// * [%\s*} %] template_end
// * {@\s*} @} template_end
// * { } template_end
// * {{# }} template_start
// * <% {\s*%> template_start
// * [% {\s*%] template_start
// * {@ {\s*@} template_start
// * {# } template_start
// * {? } template_start
// * {^ } template_start
// * {@ } template_start
// * {< } template_start
// * {+ } template_start
// * xml
let igcount:number = 0,
element:string = "",
lastchar:string = "",
ltype:string = "",
tname:string = "",
start:string = "",
cheat:boolean = false,
earlyexit:boolean = false,
ignoreme:boolean = false,
jscom:boolean = false,
nopush:boolean = false,
nosort:boolean = false,
preserve:boolean = false,
simple:boolean = false,
singleton:boolean = false,
attstore:attStore = [],
comm:[string, number] = ["", 0];
const record:record = {
begin: parse.structure[parse.structure.length - 1][1],
ender: -1,
lexer: "markup",
lines: parse.linesSpace,
stack: parse.structure[parse.structure.length - 1][0],
token: "",
types: ""
},
//cftags is a list of supported coldfusion tags
// * required - means must have a separate matching end tag
// * optional - means the tag could have a separate end tag, but is probably a
// singleton
// * prohibited - means there is no corresponding end tag
cftags = {
"cfNTauthenticate" : "optional",
"cfabort" : "prohibited",
"cfajaximport" : "optional",
"cfajaxproxy" : "optional",
"cfapplet" : "prohibited",
"cfapplication" : "prohibited",
"cfargument" : "prohibited",
"cfassociate" : "prohibited",
"cfauthenticate" : "prohibited",
"cfbreak" : "prohibited",
"cfcache" : "optional",
"cfcalendar" : "optional",
"cfcase" : "required",
"cfcatch" : "required",
"cfchart" : "optional",
"cfchartdata" : "prohibited",
"cfchartseries" : "optional",
"cfclient" : "required",
"cfclientsettings" : "optional",
"cfcol" : "prohibited",
"cfcollection" : "prohibited",
"cfcomponent" : "required",
"cfcontent" : "optional",
"cfcontinue" : "prohibited",
"cfcookie" : "prohibited",
"cfdbinfo" : "prohibited",
"cfdefaultcase" : "required",
"cfdirectory" : "prohibited",
"cfdiv" : "optional",
"cfdocument" : "optional",
"cfdocumentitem" : "optional",
"cfdocumentsection" : "optional",
"cfdump" : "optional",
"cfelse" : "prohibited",
"cfelseif" : "prohibited",
"cferror" : "prohibited",
"cfexchangecalendar" : "optional",
"cfexchangeconnection" : "optional",
"cfexchangecontact" : "optional",
"cfexchangeconversation": "optional",
"cfexchangefilter" : "optional",
"cfexchangefolder" : "optional",
"cfexchangemail" : "optional",
"cfexchangetask" : "optional",
"cfexecute" : "required",
"cfexit" : "prohibited",
"cffeed" : "prohibited",
"cffile" : "optional",
"cffileupload" : "optional",
"cffinally" : "required",
"cfflush" : "prohibited",
"cfform" : "required",
"cfformgroup" : "required",
"cfformitem" : "optional",
"cfforward" : "prohibited",
"cfftp" : "prohibited",
"cffunction" : "required",
"cfgraph" : "required",
"cfgraphdata" : "prohibited",
"cfgrid" : "required",
"cfgridcolumn" : "optional",
"cfgridrow" : "optional",
"cfgridupdate" : "optional",
"cfheader" : "prohibited",
"cfhtmlbody" : "optional",
"cfhtmlhead" : "optional",
"cfhtmltopdf" : "optional",
"cfhtmltopdfitem" : "optional",
"cfhttp" : "optional",
"cfhttpparam" : "prohibited",
"cfif" : "required",
"cfimage" : "prohibited",
"cfimap" : "prohibited",
"cfimapfilter" : "optional",
"cfimport" : "prohibited",
"cfinclude" : "prohibited",
"cfindex" : "prohibited",
"cfinput" : "prohibited",
"cfinsert" : "prohibited",
"cfinterface" : "required",
"cfinvoke" : "optional",
"cfinvokeargument" : "prohibited",
"cflayout" : "optional",
"cflayoutarea" : "optional",
"cfldap" : "prohibited",
"cflocation" : "prohibited",
"cflock" : "required",
"cflog" : "prohibited",
"cflogic" : "required",
"cfloginuser" : "prohibited",
"cflogout" : "prohibited",
"cfloop" : "required",
"cfmail" : "required",
"cfmailparam" : "prohibited",
"cfmailpart" : "required",
"cfmap" : "optional",
"cfmapitem" : "optional",
"cfmediaplayer" : "optional",
"cfmenu" : "required",
"cfmenuitem" : "optional",
"cfmessagebox" : "optional",
"cfmodule" : "optional",
"cfoauth" : "optional",
"cfobject" : "prohibited",
"cfobjectcache" : "prohibited",
"cfoutput" : "required",
"cfpageencoding" : "optional",
"cfparam" : "prohibited",
"cfpdf" : "optional",
"cfpdfform" : "optional",
"cfpdfformparam" : "optional",
"cfpdfparam" : "prohibited",
"cfpdfsubform" : "required",
"cfpod" : "optional",
"cfpop" : "prohibited",
"cfpresentation" : "required",
"cfpresentationslide" : "optional",
"cfpresenter" : "optional",
"cfprint" : "optional",
"cfprocessingdirective" : "optional",
"cfprocparam" : "prohibited",
"cfprocresult" : "prohibited",
"cfprogressbar" : "optional",
"cfproperty" : "prohibited",
"cfquery" : "required",
"cfqueryparam" : "prohibited",
"cfregistry" : "prohibited",
"cfreport" : "optional",
"cfreportparam" : "optional",
"cfrethrow" : "prohibited",
"cfretry" : "prohibited",
"cfreturn" : "prohibited",
"cfsavecontent" : "required",
"cfschedule" : "prohibited",
"cfscript" : "required",
"cfsearch" : "prohibited",
"cfselect" : "required",
"cfservlet" : "prohibited",
"cfservletparam" : "prohibited",
"cfset" : "prohibited",
"cfsetting" : "optional",
"cfsharepoint" : "optional",
"cfsilent" : "required",
"cfsleep" : "prohibited",
"cfslider" : "prohibited",
"cfspreadsheet" : "optional",
"cfsprydataset" : "optional",
"cfstatic" : "required",
"cfstopwatch" : "required",
"cfstoredproc" : "optional",
"cfswitch" : "required",
"cftable" : "required",
"cftextarea" : "optional",
"cfthread" : "optional",
"cfthrow" : "prohibited",
"cftimer" : "required",
"cftooltip" : "required",
"cftrace" : "optional",
"cftransaction" : "required",
"cftree" : "required",
"cftreeitem" : "optional",
"cftry" : "required",
"cfupdate" : "prohibited",
"cfvideo" : "prohibited",
"cfvideoplayer" : "optional",
"cfwddx" : "prohibited",
"cfwebsocket" : "optional",
"cfwhile" : "required",
"cfwindow" : "optional",
"cfx_" : "prohibited",
"cfxml" : "required",
"cfzip" : "optional",
"cfzipparam" : "prohibited"
},
//attribute name
arname = function lexer_markup_tag_name(x:string):[string, string] {
const eq:number = x.indexOf("=");
if (eq > 0 && ((eq < x.indexOf("\"") && x.indexOf("\"") > 0) || (eq < x.indexOf("'") && x.indexOf("'") > 0))) {
return [x.slice(0, eq), x.slice(eq + 1)];
}
return [x, ""];
},
// attribute parser
attributeRecord = function lexer_markup_tag_attributeRecord():void {
let ind:number = 0,
eq:number = 0,
dq:number = 0,
sq:number = 0,
slice:string = "",
name:string = "",
cft:string = cftags[
tname
.toLowerCase()
.replace(/\/$/, "")
],
store:string[] = [];
const len:number = attstore.length,
qc:"none"|"double"|"single" = (options.lexerOptions.markup.quote_convert === undefined)
? "none"
: options.lexerOptions.markup.quote_convert,
begin:number = parse.count,
stack:string = tname.replace(/\/$/, ""),
syntax:string = "<{\"'=/",
convertQ = function lexer_markup_tag_attributeRecord_convertQ():void {
if (ignoreme === true || qc === "none" || record.types !== "attribute" || (qc === "single" && record.token.indexOf("\"") < 0) || (qc === "double" && record.token.indexOf("'") < 0)) {
recordPush(data, record, "");
} else {
let ee:number = 0,
inner:boolean = false;
const chars:string[] = record.token.split(""),
eq:number = record.token.indexOf("="),
len:number = chars.length - 1;
if (chars[eq + 1] !== "\"" && qc === "single" && chars[chars.length - 1] !== "\"") {
recordPush(data, record, "");
} else if (chars[eq + 1] !== "'" && qc === "double" && chars[chars.length - 1] !== "'") {
recordPush(data, record, "");
} else {
ee = eq + 2;
if (qc === "double") {
if (record.token.slice(eq + 2, len).indexOf("\"") > -1) {
inner = true;
}
chars[eq + 1] = "\"";
chars[chars.length - 1] = "\"";
} else {
if (record.token.slice(eq + 2, len).indexOf("'") > -1) {
inner = true;
}
chars[eq + 1] = "'";
chars[chars.length - 1] = "'";
}
if (inner === true) {
do {
if (chars[ee] === "'" && qc === "single") {
chars[ee] = "\"";
} else if (chars[ee] === "\"" && qc === "double") {
chars[ee] = "'";
}
ee = ee + 1;
} while (ee < len);
}
record.token = chars.join("");
recordPush(data, record, "");
}
}
},
templateAtt = function lexer_markup_tag_attributeRecord_templateAtt(sample:string, token:string):void {
if (sample.charAt(0) === "{" && "{%#@:/?^<+~=".indexOf(sample.charAt(1)) > -1) {
record.types = "template_attribute";
} else if (sample.charAt(0) === "<") {
record.types = "template_attribute";
} else if (sample === "[%") {
record.types = "template_attribute";
} else {
record.token = token;
convertQ();
return;
}
record.token = token;
convertQ();
record.types = "attribute";
};
if (attstore.length < 1) {
return;
}
// fix for singleton tags, since "/" at the end of the tag is not an attribute
if (attstore[attstore.length - 1][0] === "/") {
attstore.pop();
element = element.replace(/>$/, "/>");
}
// reconnects attribute names to their respective values if separated on "="
eq = attstore.length;
dq = 1;
if (dq < eq) {
do {
name = attstore[dq - 1][0];
if (name.charAt(name.length - 1) === "=" && attstore[dq][0].indexOf("=") < 0) {
attstore[dq - 1][0] = name + attstore[dq][0];
attstore.splice(dq, 1);
eq = eq - 1;
dq = dq - 1;
}
dq = dq + 1;
} while (dq < eq);
}
// sort the attributes
if (options.lexerOptions.markup.tagSort === true && jscom === false && options.language !== "jsx" && nosort === false && tname !== "cfif" && tname !== "cfelseif" && tname !== "cfset") {
attstore = parse.safeSort(attstore, "", false);
}
// preparation for a coldfusion edge case
if (tname.slice(0, 3).toLowerCase() === "cf_") {
cft = "required";
}
record.begin = begin;
record.stack = stack;
record.types = "attribute";
if (ind < len) {
do {
if (attstore[ind] === undefined) {
break;
}
attstore[ind][0] = attstore[ind][0].replace(/\s+$/, "");
record.lines = attstore[ind][1];
eq = attstore[ind][0].indexOf("=");
dq = attstore[ind][0].indexOf("\"");
sq = attstore[ind][0].indexOf("'");
if ((/^\/(\/|\*)/).test(attstore[ind][0]) === true && options.language === "jsx") {
record.types = "comment_attribute";
record.token = attstore[ind][0];
convertQ();
} else if (eq > -1 && store.length > 0) {
// put certain attributes together for coldfusion
record.token = store.join(" ");
convertQ();
if (attstore[ind][0].indexOf("=") > 0 && attstore[ind][0].indexOf("//") < 0 && attstore[ind][0].charAt(0) !== ";") {
record.token = attstore[ind][0].replace(/\s$/, "");
} else {
record.token = attstore[ind][0];
}
convertQ();
store = [];
} else if (ltype === "sgml") {
store.push(attstore[ind][0]);
} else if (cft !== undefined && eq < 0 && attstore[ind][0].indexOf("=") < 0) {
// put certain attributes together for coldfusion
store.push(attstore[ind][0]);
} else if ((cft !== undefined && eq < 0) || (dq > 0 && dq < eq) || (sq > 0 && sq < eq) || syntax.indexOf(attstore[ind][0].charAt(0)) > -1) {
// tags stored as attributes of other tags
templateAtt(attstore[ind][0].replace(/^("|')/, "").slice(0, 2), attstore[ind][0].replace(/\s$/, ""));
} else if (eq < 0 && cft === undefined) {
// in most markup languages an attribute without an expressed value has its name
// as its string value
if (options.language === "html") {
record.token = attstore[ind][0].toLowerCase();
} else if (options.language === "xml" || options.language === "coldfusion") {
if (options.lexerOptions.markup.quote_convert === "single") {
record.token = `${attstore[ind][0]}='${attstore[ind][0]}'`;
} else {
record.token = `${attstore[ind][0]}="${attstore[ind][0]}"`;
}
} else {
record.token = attstore[ind][0];
}
convertQ();
} else {
// separates out the attribute name from its value
slice = attstore[ind][0].slice(eq + 1);
if (syntax.indexOf(slice.charAt(0)) < 0 && cft === undefined) {
slice = "\"" + slice + "\"";
}
name = attstore[ind][0].slice(0, eq);
if (options.language === "html" && cft === undefined) {
name = name.toLowerCase();
}
if (options.language === "jsx" && (/^(\s*\{)/).test(slice) === true) {
record.token = name + "={";
record.types = "jsx_attribute_start";
recordPush(data, record, "jsx_attribute");
framework.lexer.script(slice.slice(1, slice.length - 1));
record.begin = parse.count;
if ((/\s\}$/).test(slice) === true) {
slice = slice.slice(0, slice.length - 1);
slice = (/\s+$/).exec(slice)[0];
if (slice.indexOf("\n") < 0) {
record.lines = 1;
} else {
record.lines = slice.split("\n").length;
}
} else {
record.lines = 0;
}
record.begin = parse.structure[parse.structure.length - 1][1];
record.stack = parse.structure[parse.structure.length - 1][0];
record.token = "}";
record.types = "jsx_attribute_end";
convertQ();
record.types = "attribute";
record.begin = begin;
record.stack = stack;
} else {
name = name + "=" + slice;
templateAtt(slice.replace(/^("|')/, "").slice(0, 2), name.replace(/(\s+)$/, ""));
}
}
ind = ind + 1;
} while (ind < len);
}
if (store.length > 0) {
record.token = store.join(" ");
convertQ();
}
};
ext = false;
// this complex series of conditions determines an elements delimiters look to
// the types being pushed to quickly reason about the logic no type is pushed
// for start tags or singleton tags just yet some types set the `preserve` flag,
// which means to preserve internal white space The `nopush` flag is set when
// parsed tags are to be ignored and forgotten
(function lexer_markup_types() {
if (end === "]>") {
end = ">";
sgmlflag = sgmlflag - 1;
ltype = "end";
} else if (end === "---") {
ltype = "comment";
start = "---";
} else if (b[a] === "<") {
if (b[a + 1] === "/") {
if (b[a + 2] === "#") {
ltype = "template_end";
} else {
ltype = "end";
}
end = ">";
} else if (b[a + 1] === "!") {
if (b[a + 2] === "-" && b[a + 3] === "-") {
if (b[a + 4] === "#") {
end = "-->";
ltype = "template";
} else if (b[a + 4] === "-" && (/" || (/\s/).test(b[a + 4]) === true)) {
end = " ";
preserve = true;
ltype = "ignore";
} else if ((b[a + 1] === "x" || b[a + 1] === "X") && (b[a + 2] === "m" || b[a + 2] === "M") && (b[a + 3] === "l" || b[a + 3] === "L") && b[a + 4] === ":" && (b[a + 5] === "t" || b[a + 5] === "T") && (b[a + 6] === "e" || b[a + 6] === "E") && (b[a + 7] === "x" || b[a + 7] === "X") && (b[a + 8] === "t" || b[a + 8] === "T") && (b[a + 9] === ">" || (/\s/).test(b[a + 9]) === true)) {
end = "";
preserve = true;
ltype = "ignore";
} else if ((b[a + 1] === "c" || b[a + 1] === "C") && (b[a + 2] === "f" || b[a + 2] === "F") && (b[a + 3] === "q" || b[a + 3] === "Q") && (b[a + 4] === "u" || b[a + 4] === "U") && (b[a + 5] === "e" || b[a + 5] === "E") && (b[a + 6] === "r" || b[a + 6] === "R") && (b[a + 7] === "y" || b[a + 7] === "Y") && (b[a + 8] === ">" || (/\s/).test(b[a + 8]) === true)) {
end = "" + b.slice(a + 1, a + 8).join("") + ">";
preserve = true;
ltype = "content_preserve";
} else if (b[a + 1] === "<") {
if (b[a + 2] === "<") {
end = ">>>";
} else {
end = ">>";
}
ltype = "template";
} else if (b[a + 1] === "#") {
if (b[a + 2] === "e" && b[a + 3] === "l" && b[a + 4] === "s" && b[a + 5] === "e") {
end = ">";
ltype = "template_else";
} else if (b[a + 2] === "-" && b[a + 3] === "-") {
end = "-->";
ltype = "comment";
start = "<#--";
} else {
end = ">";
ltype = "template_start";
}
} else {
simple = true;
end = ">";
}
} else if (b[a] === "{") {
preserve = true;
if (options.language === "jsx") {
ext = true;
earlyexit = true;
record.token = "{";
record.types = "script_start";
recordPush(data, record, "");
parse.structure.push(["script", parse.count]);
return;
}
if (options.language === "dustjs") {
if (b[a + 1] === ":" && b[a + 2] === "e" && b[a + 3] === "l" && b[a + 4] === "s" && b[a + 5] === "e" && b[a + 6] === "}") {
a = a + 6;
earlyexit = true;
record.token = "{:else}";
record.types = "template_else";
recordPush(data, record, "");
return;
}
if (b[a + 1] === "!") {
end = "!}";
ltype = "comment";
start = "{!";
} else if (b[a + 1] === "/") {
end = "}";
ltype = "template_end";
} else if (b[a + 1] === "~") {
end = "}";
ltype = "singleton";
} else if (b[a + 1] === ">") {
end = "/}";
ltype = "singleton";
} else if (b[a + 1] === "#" || b[a + 1] === "?" || b[a + 1] === "^" || b[a + 1] === "@" || b[a + 1] === "<" || b[a + 1] === "+") {
end = "}";
ltype = "template_start";
} else {
end = "}";
ltype = "template";
}
} else if (b[a + 1] === "{") {
if (b[a + 2] === "{") {
end = "}}}";
ltype = "template";
} else if (b[a + 2] === "#") {
end = "}}";
ltype = "template_start";
} else if (b[a + 2] === "/") {
end = "}}";
ltype = "template_end";
} else if (b[a + 2] === "e" && b[a + 3] === "n" && b[a + 4] === "d") {
end = "}}";
ltype = "template_end";
} else if (b[a + 2] === "e" && b[a + 3] === "l" && b[a + 4] === "s" && b[a + 5] === "e") {
end = "}}";
ltype = "template_else";
} else {
end = "}}";
ltype = "template";
}
} else if (b[a + 1] === "%") {
end = "%}";
ltype = "template";
} else if (b[a + 1] === "#") {
end = "#}";
ltype = "comment";
start = "{#";
} else {
end = b[a + 1] + "}";
ltype = "template";
}
if (b[a + 1] === "@" && b[a + 2] === "}" && b[a + 3] === "e" && b[a + 4] === "l" && b[a + 5] === "s" && b[a + 6] === "e" && b[a + 7] === "{" && b[a + 8] === "@" && b[a + 9] === "}") {
a = a + 9;
earlyexit = true;
record.token = "{@}else{@}";
record.types = "template_else";
recordPush(data, record, "");
return;
}
} else if (b[a] === "[" && b[a + 1] === "%") {
end = "%]";
ltype = "template";
} else if (b[a] === "#" && options.language === "apacheVelocity") {
if (b[a + 1] === "*") {
end = "*#";
ltype = "comment";
start = "#*";
} else if (b[a + 1] === "[" && b[a + 2] === "[") {
end = "]]#";
ltype = "comment";
start = "#[["
} else if (b[a + 1] === "#") {
end = "\n";
ltype = "comment";
start = "##";
} else if (b[a + 1] === "e" && b[a + 2] === "l" && b[a + 3] === "s" && b[a + 4] === "e" && (/\s/).test(b[a + 5]) === true) {
end = "\n";
ltype = "template_else";
} else if (b[a + 1] === "i" && b[a + 2] === "f") {
end = "\n";
ltype = "template_start";
} else if (b[a + 1] === "f" && b[a + 2] === "o" && b[a + 3] === "r" && b[a + 4] === "e" && b[a + 5] === "a" && b[a + 6] === "c" && b[a + 7] === "h") {
end = "\n";
ltype = "template_start";
} else if (b[a + 1] === "e" && b[a + 2] === "n" && b[a + 3] === "d") {
end = "\n";
ltype = "template_end";
} else {
end = "\n";
ltype = "template";
}
} else if (b[a] === "$" && options.language === "apacheVelocity") {
end = "\n";
ltype = "template";
}
if (options.lexerOptions.markup.unformatted === true) {
preserve = true;
}
}());
if (earlyexit === true) {
return;
}
// This is the real tag lexer. Everything that follows is attribute handling and
// edge cases
lastchar = end.charAt(end.length - 1);
if (ltype === "comment" && b[a] === "<") {
comm = parse.wrapCommentBlock({
chars: b,
end: c,
lexer: "markup",
opening: start,
start: a,
terminator: end
});
element = comm[0];
a = comm[1];
if (element.replace(start, "").replace(/(^\s*)/, "").indexOf("parse-ignore-start") === 0) {
record.token = element;
record.types = "ignore";
recordPush(data, record, "");
return;
}
} else if (a < c) {
let bcount:number = 0,
braccount:number = 0,
jsxcount:number = 0,
e:number = 0,
f:number = 0,
parncount:number = 0,
lines:number = 1,
quote:string = "",
jsxquote:string = "",
stest:boolean = false,
quotetest:boolean = false,
dustatt:string[] = [],
attribute:string[] = [];
const lex:string[] = [],
//finds slash escape sequences
slashy = function lexer_markup_tag_slashy():boolean {
let x:number = a;
do {
x = x - 1;
} while (b[x] === "\\");
x = a - x;
if (x % 2 === 1) {
return false;
}
return true;
},
// attribute lexer
attributeLexer = function lexer_markup_tag_attributeLexer(quotes:boolean):void {
let atty:string = "",
name:[string, string],
aa:number = 0,
bb:number = 0;
if (quotes === true) {
atty = attribute.join("");
name = arname(atty);
if (name[0] === "data-parse-ignore" || name[0] === "data-prettydiff-ignore") {
ignoreme = true;
}
quote = "";
} else {
atty = attribute
.join("");
if (options.language !== "jsx" || (options.language === "jsx" && atty.charAt(atty.length - 1) !== "}")) {
atty = atty.replace(/\s+/g, " ");
}
name = arname(atty);
if (name[0] === "data-parse-ignore" || name[0] === "data-prettydiff-ignore") {
ignoreme = true;
}
if (options.language === "jsx" && attribute[0] === "{" && attribute[attribute.length - 1] === "}") {
jsxcount = 0;
}
}
if (atty.slice(0, 3) === "<%=" || atty.slice(0, 2) === "{%") {
nosort = true;
}
atty = atty
.replace(/^\u0020/, "")
.replace(/\u0020$/, "");
attribute = atty
.replace(/\r\n/g, "\n")
.split("\n");
bb = attribute.length;
if (aa < bb) {
do {
attribute[aa] = attribute[aa].replace(/(\s+)$/, "");
aa = aa + 1;
} while (aa < bb);
}
if (options.crlf === true) {
atty = attribute.join("\r\n");
} else {
atty = attribute.join("\n");
}
if (atty === "=") {
attstore[attstore.length - 1][0] = `${attstore[attstore.length - 1][0]}=`;
} else if (atty.charAt(0) === "=" && attstore.length > 0 && attstore[attstore.length - 1][0].indexOf("=") < 0) {
//if an attribute starts with a `=` then adjoin it to the last attribute
attstore[attstore.length - 1][0] = attstore[attstore.length - 1][0] + atty;
} else if (atty.charAt(0) !== "=" && attstore.length > 0 && attstore[attstore.length - 1][0].indexOf("=") === attstore[attstore.length - 1][0].length - 1) {
// if an attribute follows an attribute ending with `=` then adjoin it to the
// last attribute
attstore[attstore.length - 1][0] = attstore[attstore.length - 1][0] + atty;
} else if (options.language === "coldfusion" && attstore.length > 0 && (("+-\u002a/(^").indexOf(atty) > -1 || ("+-\u002a/(^").indexOf(attstore[attstore.length - 1][0].charAt(attstore[attstore.length - 1][0].length - 1)) > -1)) {
attstore[attstore.length - 1][0] = `${attstore[attstore.length - 1][0]} ${atty}`;
} else if (atty !== "" && atty !== " ") {
attstore.push([atty, lines]);
}
if (attstore.length > 0 && attstore[attstore.length - 1][0].indexOf("=\u201c") > 0) {
framework.parseerror = `Quote looking character (\u201c, “) used instead of actual quotes on line number ${parse.lineNumber}`;
} else if (attstore.length > 0 && attstore[attstore.length - 1][0].indexOf("=\u201d") > 0) {
framework.parseerror = `Quote looking character (\u201d, ”) used instead of actual quotes on line number ${parse.lineNumber}`;
}
attribute = [];
lines = (b[a] === "\n")
? 2
: 1;
};
do {
if (b[a] === "\n") {
lines = lines + 1;
if (options.language === "apacheVelocity" && lex[0] === "#") {
a = a - 1;
break;
}
parse.lineNumber = parse.lineNumber + 1;
}
if (preserve === true || (((/\s/).test(b[a]) === false && quote !== "}") || quote === "}")) {
lex.push(b[a]);
if (lex[0] === "<" && lex[1] === ">" && end === ">") {
record.token = "<>";
record.types = "start";
recordPush(data, record, "(empty)");
return;
}
if (lex[0] === "<" && lex[1] === "/" && lex[2] === ">" && end === ">") {
record.token = ">";
record.types = "end";
recordPush(data, record, "");
return;
}
}
if (ltype === "cdata" && b[a] === ">" && b[a - 1] === "]" && b[a - 2] !== "]") {
framework.parseerror = `CDATA tag ${lex.join("")} is not properly terminated with ]]>`;
break;
}
if (ltype === "comment") {
quote = "";
//comments must ignore fancy encapsulations and attribute parsing
if (b[a] === lastchar && lex.length > end.length + 1) {
//if current character matches the last character of the tag ending sequence
f = lex.length;
e = end.length - 1;
if (e > -1) {
do {
f = f - 1;
if (lex[f] !== end.charAt(e)) {
break;
}
e = e - 1;
} while (e > -1);
}
if (e < 0) {
if (end === "endcomment") {
f = f - 1;
if ((/\s/).test(lex[f]) === true) {
do {
f = f - 1;
} while (f > 0 && (/\s/).test(lex[f]) === true);
}
if (lex[f - 1] === "{" && lex[f] === "%") {
end = "%}";
lastchar = "}";
}
} else {
break;
}
}
}
} else {
if (quote === "") {
if (lex[0] + lex[1] === "" && b[a + 1] === "<") {
framework.parseerror = `SGML tag ${lex.join("")} is missing termination with '[' or '>'.`
break;
}
}
if (options.language === "jsx") {
if (b[a] === "{") {
jsxcount = jsxcount + 1;
} else if (b[a] === "}") {
jsxcount = jsxcount - 1;
}
}
if (data.types[parse.count] === "sgml" && b[a] === "[" && lex.length > 4) {
data.types[parse.count] = "template_start";
count.start = count.start + 1;
break;
}
if (b[a] === "<" && options.language !== "coldfusion" && preserve === false && lex.length > 1 && end !== ">>" && end !== ">>>" && simple === true) {
framework.parseerror = `Parse error on line ${parse.lineNumber} on element: ${lex.join("")}`;
}
if (stest === true && (/\s/).test(b[a]) === false && b[a] !== lastchar) {
//attribute start
stest = false;
quote = jsxquote;
igcount = 0;
lex.pop();
if (a < c) {
do {
if (b[a] === "\n") {
parse.lineNumber = parse.lineNumber + 1;
}
if (options.lexerOptions.markup.unformatted === true) {
lex.push(b[a]);
}
attribute.push(b[a]);
if ((b[a] === "<" || b[a] === ">") && (quote === "" || quote === ">") && options.language !== "jsx") {
if (quote === "" && b[a] === "<") {
quote = ">";
braccount = 1;
} else if (quote === ">") {
if (b[a] === "<") {
braccount = braccount + 1;
} else if (b[a] === ">") {
braccount = braccount - 1;
if (braccount === 0) {
// the following detects if a coldfusion tag is embedded within another markup
// tag
tname = tagName(attribute.join(""));
if (cftags[tname] === "required") {
quote = "" + tname + ">";
} else {
quote = "";
igcount = 0;
attributeLexer(false);
break;
}
}
}
}
} else if (quote === "") {
if (b[a + 1] === lastchar) {
//if at end of tag
if (attribute[attribute.length - 1] === "/" || (attribute[attribute.length - 1] === "?" && ltype === "xml")) {
attribute.pop();
if (preserve === true) {
lex.pop();
}
a = a - 1;
}
if (attribute.length > 0) {
attributeLexer(false);
}
break;
}
if ((/^=?("|')?((\{(\{|%|#|@|:|\/|\?|\^|<|\+|~|=))|(\[%)|<)/).test(b[a] + b[a + 1] + b[a + 2] + b[a + 3]) === true) {
attribute.pop();
if (b[a] !== "=" && attribute.length > 0) {
attributeLexer(false);
}
quote = "";
do {
attribute.push(b[a]);
if (b[a] === dustatt[dustatt.length - 1]) {
dustatt.pop();
if (b[a] === "}" && b[a + 1] === "}") {
attribute.push("}");
a = a + 1;
if (b[a + 1] === "}") {
attribute.push("}");
a = a + 1;
}
}
if (dustatt.length < 1) {
attributeLexer(false);
b[a] = " ";
break;
}
} else if ((b[a] === "\"" || b[a] === "'") && dustatt[dustatt.length - 1] !== "\"" && dustatt[dustatt.length - 1] !== "'") {
dustatt.push(b[a]);
} else if (b[a] === "{" && "{%#@:/?^<+~=".indexOf(b[a + 1]) && dustatt[dustatt.length - 1] !== "}") {
dustatt.push("}");
} else if (b[a] === "<" && dustatt[dustatt.length - 1] !== ">") {
dustatt.push(">");
} else if (b[a] === "[" && b[a + 1] === ":" && dustatt[dustatt.length - 1] !== "]") {
dustatt.push("]");
}
a = a + 1;
} while (a < c);
} else if (b[a] === "{" && b[a - 1] === "=" && options.language !== "jsx") {
quote = "}";
} else if (b[a] === "\"" || b[a] === "'") {
quote = b[a];
if (
b[a - 1] === "=" &&
(
b[a + 1] === "<" ||
(b[a + 1] === "{" && b[a + 2] === "%") ||
((/\s/).test(b[a + 1]) === true && b[a - 1] !== "=")
)
) {
igcount = a;
}
} else if (b[a] === "(") {
quote = ")";
parncount = 1;
} else if (options.language === "jsx") {
//jsx variable attribute
if ((b[a - 1] === "=" || (/\s/).test(b[a - 1]) === true) && b[a] === "{") {
quote = "}";
bcount = 1;
} else if (b[a] === "/") {
//jsx comments
if (b[a + 1] === "*") {
quote = "\u002a/";
} else if (b[a + 1] === "/") {
quote = "\n";
}
}
} else if (lex[0] !== "{" && b[a] === "{" && (b[a + 1] === "{" || b[a + 1] === "%" || b[a + 1] === "@" || b[a + 1] === "#")) {
//opening embedded template expression
if (b[a + 1] === "{") {
if (b[a + 2] === "{") {
quote = "}}}";
} else {
quote = "}}";
}
} else {
quote = b[a + 1] + "}";
}
}
if ((/\s/).test(b[a]) === true && quote === "") {
// testing for a run of spaces between an attribute's = and a quoted value.
// Unquoted values separated by space are separate attributes
if (attribute[attribute.length - 2] === "=") {
e = a + 1;
if (e < c) {
do {
if ((/\s/).test(b[e]) === false) {
if (b[e] === "\"" || b[e] === "'") {
a = e - 1;
quotetest = true;
attribute.pop();
}
break;
}
e = e + 1;
} while (e < c);
}
}
if (quotetest === true) {
quotetest = false;
} else if (jsxcount === 0 || (jsxcount === 1 && attribute[0] === "{")) {
//if there is an unquoted space attribute is complete
attribute.pop();
attributeLexer(false);
stest = true;
break;
}
}
} else if (b[a] === "(" && quote === ")") {
parncount = parncount + 1;
} else if (b[a] === ")" && quote === ")") {
parncount = parncount - 1;
if (parncount === 0) {
quote = "";
if (b[a + 1] === end.charAt(0)) {
attributeLexer(false);
break;
}
}
} else if (options.language === "jsx" && (quote === "}" || (quote === "\n" && b[a] === "\n") || (quote === "\u002a/" && b[a - 1] === "*" && b[a] === "/"))) {
//jsx attributes
if (quote === "}") {
if (b[a] === "{") {
bcount = bcount + 1;
} else if (b[a] === quote) {
bcount = bcount - 1;
if (bcount === 0) {
jsxcount = 0;
quote = "";
element = attribute.join("");
if (options.lexerOptions.markup.unformatted === false) {
if (options.language === "jsx") {
if ((/^(\s*)$/).test(element) === false) {
attstore.push([element, lines]);
}
} else {
element = element.replace(/\s+/g, " ");
if (element !== " ") {
attstore.push([element, lines]);
}
}
} else if ((/^(\s+)$/).test(element) === false) {
attstore.push([element, lines]);
}
attribute = [];
lines = 1;
break;
}
}
} else {
jsxquote = "";
jscom = true;
element = attribute.join("");
if (element !== " ") {
attstore.push([element, lines]);
}
attribute = [];
lines = (quote === "\n")
? 2
: 1;
quote = "";
break;
}
} else if (b[a] === "{" && b[a + 1] === "%" && b[igcount - 1] === "=" && (quote === "\"" || quote === "'")) {
quote = quote + "{%";
igcount = 0;
} else if (b[a - 1] === "%" && b[a] === "}" && (quote === "\"{%" || quote === "'{%")) {
quote = quote.charAt(0);
igcount = 0;
} else if (b[a] === "<" && end === ">" && b[igcount - 1] === "=" && (quote === "\"" || quote === "'")) {
quote = quote + "<";
igcount = 0;
} else if (b[a] === ">" && (quote === "\"<" || quote === "'<")) {
quote = quote.charAt(0);
igcount = 0;
} else if (igcount === 0 && quote !== ">" && (quote.length < 2 || (quote.charAt(0) !== "\"" && quote.charAt(0) !== "'"))) {
//terminate attribute at the conclusion of a quote pair
f = 0;
if (lex.length > 1) {
tname = lex[1] + lex[2];
tname = tname.toLowerCase();
}
// in coldfusion quotes are escaped in a string with double the characters:
// "cat"" and dog"
if (tname === "cf" && b[a] === b[a + 1] && (b[a] === "\"" || b[a] === "'")) {
attribute.push(b[a + 1]);
a = a + 1;
} else {
e = quote.length - 1;
if (e > -1) {
do {
if (b[a - f] !== quote.charAt(e)) {
break;
}
f = f + 1;
e = e - 1;
} while (e > -1);
}
if (e < 0) {
attributeLexer(true);
if (b[a + 1] === lastchar) {
break;
}
}
}
} else if (igcount > 0 && (/\s/).test(b[a]) === false) {
igcount = 0;
}
a = a + 1;
} while (a < c);
}
} else if (end !== "%>" && end !== "\n" && (b[a] === "\"" || b[a] === "'")) {
//opening quote
quote = b[a];
} else if (ltype !== "comment" && end !== "\n" && b[a] === "<" && b[a + 1] === "!" && b[a + 2] === "-" && b[a + 3] === "-" && b[a + 4] !== "#" && data.types[parse.count] !== "conditional") {
quote = "-->";
} else if (b[a] === "{" && lex[0] !== "{" && end !== "\n" && end !== "%>" && end !== "%]" && (options.language === "dustjs" || b[a + 1] === "{" || b[a + 1] === "%" || b[a + 1] === "@" || b[a + 1] === "#")) {
//opening embedded template expression
if (b[a + 1] === "{") {
if (b[a + 2] === "{") {
quote = "}}}";
} else {
quote = "}}";
}
} else if (options.language === "dustjs") {
if (attribute.length < 1 && (attstore.length < 1 || (/\s/).test(b[a - 1]) === true)) {
lex.pop();
do {
if (b[a] === "\n") {
lines = lines + 1;
}
attribute.push(b[a]);
a = a + 1;
} while (a < c && b[a] !== "}");
attribute.push("}");
attstore.push([attribute.join(""), lines]);
attribute = [];
lines = 1;
} else {
quote = "}";
}
} else {
quote = b[a + 1] + "}";
if (attribute.length < 1 && (attstore.length < 1 || (/\s/).test(b[a - 1]) === true)) {
lex.pop();
do {
if (b[a] === "\n") {
lines = lines + 1;
}
attribute.push(b[a]);
a = a + 1;
} while (a < c && b[a - 1] + b[a] !== quote);
attribute.push("}");
attstore.push([attribute.join(""), lines]);
attribute = [];
lines = 1;
quote = "";
}
}
if (quote === end) {
quote = "";
}
} else if ((simple === true || ltype === "sgml") && end !== "\n" && (/\s/).test(b[a]) === true && b[a - 1] !== "<") {
//identify a space in a regular start or singleton tag
if (ltype === "sgml") {
lex.push(" ");
} else {
stest = true;
}
} else if (simple === true && options.language === "jsx" && b[a] === "/" && (b[a + 1] === "*" || b[a + 1] === "/")) {
//jsx comment immediately following tag name
stest = true;
lex[lex.length - 1] = " ";
attribute.push(b[a]);
if (b[a + 1] === "*") {
jsxquote = "\u002a/";
} else {
jsxquote = "\n";
}
} else if ((b[a] === lastchar || (end === "\n" && b[a + 1] === "<")) && (lex.length > end.length + 1 || lex[0] === "]") && (options.language !== "jsx" || jsxcount === 0)) {
if (end === "\n") {
if ((/\s/).test(lex[lex.length - 1]) === true) {
do {
lex.pop();
a = a - 1;
} while ((/\s/).test(lex[lex.length - 1]) === true);
}
break;
}
if (lex[0] === "{" && lex[1] === "%" && lex.join("").replace(/\s+/g, "") === "{%comment%}") {
end = "endcomment";
lastchar = "t";
preserve = true;
ltype = "comment";
} else {
//if current character matches the last character of the tag ending sequence
f = lex.length;
e = end.length - 1;
if (e > -1) {
do {
f = f - 1;
if (lex[f] !== end.charAt(e)) {
break;
}
e = e - 1;
} while (e > -1);
}
if (e < 0) {
break;
}
}
}
} else if (b[a] === quote.charAt(quote.length - 1) && ((options.language === "jsx" && end === "}" && (b[a - 1] !== "\\" || slashy() === false)) || options.language !== "jsx" || end !== "}")) {
//find the closing quote or embedded template expression
f = 0;
if (lex.length > 1) {
tname = lex[1] + lex[2];
tname = tname.toLowerCase();
}
// in coldfusion quotes are escaped in a string with double the characters:
// "cat"" and dog"
if (tname === "cf" && b[a] === b[a + 1] && (b[a] === "\"" || b[a] === "'")) {
attribute.push(b[a + 1]);
a = a + 1;
} else {
e = quote.length - 1;
if (e > -1) {
do {
if (b[a - f] !== quote.charAt(e)) {
break;
}
f = f + 1;
e = e - 1;
} while (e > -1);
}
if (e < 0) {
quote = "";
}
}
}
}
a = a + 1;
} while (a < c);
//nopush flags mean an early exit
if (nopush) {
return;
}
//a correction to incomplete template tags that use multiple angle braces
if (options.correct === true) {
if (b[a + 1] === ">" && lex[0] === "<" && lex[1] !== "<") {
do {
a = a + 1;
} while (b[a + 1] === ">");
} else if (lex[0] === "<" && lex[1] === "<" && b[a + 1] !== ">" && lex[lex.length - 2] !== ">") {
do {
lex.splice(1, 1);
} while (lex[1] === "<");
}
}
igcount = 0;
element = lex.join("");
if (element.replace(start, "").replace(/^\s+/, "").indexOf("parse-ignore-start") === 0) {
a = a + 1;
do {
lex.push(b[a]);
if (b[a] === "d" && lex.slice(lex.length - 16).join("") === "parse-ignore-end") {
break;
}
a = a + 1;
} while (a < c);
do {
lex.push(b[a]);
if (b[a] === end.charAt(end.length - 1) && b.slice(a - (end.length - 1), a + 1).join("") === end) {
break;
}
a = a + 1;
} while (a < c);
record.token = lex.join("");
record.types = "ignore";
recordPush(data, record, "");
return;
}
}
record.token = element;
record.types = ltype;
tname = tagName(element);
if ((/^(\/?cf)/i).test(tname) === true) {
tname = tname
.toLowerCase()
.replace(/\/$/, "")
.replace(/^\//, "");
}
if (preserve === false && options.language !== "jsx") {
element = element.replace(/\s+/g, " ");
}
//a quick hack to inject records for a type of template comments
if (tname === "comment" && element.slice(0, 2) === "{%") {
element = element
.replace(/^(\{%\s*comment\s*%\}\s*)/, "")
.replace(/(\s*\{%\s*endcomment\s*%\})$/, "");
record.token = "{% comment %}";
record.types = "template_start";
recordPush(data, record, "");
record.token = element;
record.types = "comment";
recordPush(data, record, "");
record.token = "{% endcomment %}";
record.types = "template_end";
recordPush(data, record, "");
return;
}
// a type correction for template tags who have variable start tag names but a
// consistent ending tag name
if (element.indexOf("{{") === 0 && element.slice(element.length - 2) === "}}") {
if (tname === "end") {
ltype = "template_end";
} else if (tname === "else") {
ltype = "template_else";
}
} else if (element.slice(0, 2) === "<%" && element.slice(element.length - 2) === "%>") {
if ((/^(<%\s+end\s+-?%>)$/).test(element) === true) {
ltype = "template_end";
} else if (((/\sdo\s/).test(element) === true && element.indexOf("-%>") === element.length - 3) || (/^(<%(%|-)?\s*if)/).test(element) === true) {
ltype = "template_start";
}
}
//update a flag for subatomic parsing in SGML tags
if (end !== "]>" && sgmlflag > 0 && element.charAt(element.length - 1) !== "[" && (element.slice(element.length - 2) === "]>" || (/^( (which is really