mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-01-03 12:42:41 +00:00
All features working...?
This commit is contained in:
@@ -32,7 +32,7 @@ renderer.paragraph = function(text){
|
|||||||
//TODO: may not be needed
|
//TODO: may not be needed
|
||||||
// Disable default reflink definitions
|
// Disable default reflink definitions
|
||||||
tokenizer.def = function(){
|
tokenizer.def = function(){
|
||||||
}
|
};
|
||||||
|
|
||||||
const mustacheSpans = {
|
const mustacheSpans = {
|
||||||
name : 'mustacheSpans',
|
name : 'mustacheSpans',
|
||||||
@@ -273,325 +273,287 @@ const definitionLists = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//v=====--------------------< Variable Handling >-------------------=====v//
|
//v=====--------------------< Variable Handling >-------------------=====v// 295 lines
|
||||||
const consumeBlockDef = {
|
const replaceVar = function(input, hoist=false) {
|
||||||
name : 'consumeBlockDef',
|
const regex = /([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)/g;
|
||||||
level : 'block',
|
const match = regex.exec(input);
|
||||||
start(src) {return src.match(/^ {0,3}[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]:/m)?.index; },
|
|
||||||
tokenizer(src, tokens) {
|
const prefix = match[1];
|
||||||
// [ variable name (spaces allowed) ]: Any text, including into newlines (but no fully blank lines)
|
const label = match[2];
|
||||||
const regex = /^ {0,3}[!$]?\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]: *((?:\n? *[^\s].*)+)(?=\n+|$)/;
|
|
||||||
const match = regex.exec(src);
|
let missingValues = [];
|
||||||
if(match) {
|
|
||||||
return {
|
//v=====--------------------< HANDLE MATH >-------------------=====v//
|
||||||
type : 'consumeBlockDef',
|
const mathRegex = /[^+\-*\/]+|[+\-*\/]/g;
|
||||||
raw : match[0],
|
let mathLabels = label.match(mathRegex).map((s)=>s.trim());
|
||||||
tokens : this.lexer.inline(`\n${match[0]}`),
|
|
||||||
};
|
if(mathLabels.length > 2 && mathLabels.length % 2 == 1) {
|
||||||
}
|
|
||||||
},
|
const valid = mathLabels.every((val, i)=>{ // Math must alternate between operators and values
|
||||||
renderer(token){
|
const isOperator = '+-*/'.includes(val);
|
||||||
return this.parser.parseInline(token.tokens);
|
return (i % 2 === 0 ? !isOperator : isOperator);
|
||||||
|
});
|
||||||
|
if(!valid)
|
||||||
|
return { value: input, missingValues: missingValues };
|
||||||
|
|
||||||
|
mathLabels = mathLabels.map((str)=>{
|
||||||
|
if(!isNaN(str))
|
||||||
|
return Number(str);
|
||||||
|
|
||||||
|
if('+-*/'.includes(str))
|
||||||
|
return str;
|
||||||
|
|
||||||
|
const foundVar = lookupVar(str, globalPageNumber, hoist);
|
||||||
|
if(foundVar && foundVar.resolved && foundVar.content) // Only subsitute math values if fully resolved and not empty strings
|
||||||
|
return foundVar.content;
|
||||||
|
|
||||||
|
return str;
|
||||||
|
});
|
||||||
|
|
||||||
|
missingValues = mathLabels.filter((x)=>isNaN(x) && !'+-*/'.includes(x));
|
||||||
|
|
||||||
|
return {
|
||||||
|
value : missingValues.length > 0 ? input : eval(mathLabels.join('')),
|
||||||
|
missingValues : missingValues
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
//^=====--------------------< HANDLE MATH >-------------------=====^//
|
||||||
|
|
||||||
|
const foundVar = lookupVar(label, globalPageNumber, hoist);
|
||||||
|
if(foundVar == undefined) {
|
||||||
|
return {
|
||||||
|
value : input,
|
||||||
|
missingValues : [label]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!foundVar.resolved) {
|
||||||
|
missingValues = [label];
|
||||||
|
}
|
||||||
|
|
||||||
|
// url or <url> "title" or 'title' or (title)
|
||||||
|
const linkRegex = /^([^<\s][^\s]*|<.*?>)(?: ("(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\((?:\\\(|\\\)|[^()])*\)))?$/m;
|
||||||
|
const linkMatch = linkRegex.exec(foundVar.content);
|
||||||
|
|
||||||
|
let href = null;
|
||||||
|
let title = null;
|
||||||
|
if(linkMatch) {
|
||||||
|
href = linkMatch[1]; //TODO: TRIM OFF < > IF PRESENT
|
||||||
|
title = linkMatch[2]?.slice(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let value;
|
||||||
|
|
||||||
|
if(!prefix[0] && href) // Link
|
||||||
|
value = `[${label}](${href} ${title ? title : ''})`;
|
||||||
|
|
||||||
|
if(prefix[0] == '!' && href) // Image
|
||||||
|
value = ``;
|
||||||
|
|
||||||
|
if(prefix[0] == '$') // Variable
|
||||||
|
value = foundVar.content;
|
||||||
|
|
||||||
|
return {
|
||||||
|
value : value,
|
||||||
|
missingValues : missingValues
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const refLinkBlockDef = {
|
const lookupVar = function(label, index, hoist=false) {
|
||||||
name : 'refLinkBlockDef',
|
if(hoist)
|
||||||
level : 'inline',
|
index = Object.keys(globalLinks).length;
|
||||||
start(src) {return src.match(/^\n {0,3}[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]:/m)?.index; },
|
|
||||||
tokenizer(src, tokens) {
|
|
||||||
// [ variable name (spaces allowed) ]: Any text, including into newlines (but no fully blank lines)
|
|
||||||
const regex = /^\n {0,3}[!$]?\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]: *((?:\n? *[^\s].*)+)(?=\n+|$)/;
|
|
||||||
const match = regex.exec(src);
|
|
||||||
if(match) {
|
|
||||||
const label = match[1] ? match[1].trim().toLowerCase().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
|
||||||
const content = match[2] ? match[2].trim().toLowerCase().replace(/[ \t]+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
|
||||||
|
|
||||||
// url or <url> "title" or 'title' or (title)
|
|
||||||
const linkRegex = /^([^<\s][^\s]*|<.*?>)(?: ("(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\((?:\\\(|\\\)|[^()])*\)))?$/m
|
|
||||||
const linkMatch = linkRegex.exec(content);
|
|
||||||
|
|
||||||
let href = null;
|
|
||||||
let title = null;
|
|
||||||
if(linkMatch) {
|
|
||||||
href = linkMatch[1];
|
|
||||||
title = linkMatch[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!globalLinks[globalPageNumber])
|
|
||||||
globalLinks[globalPageNumber] = {};
|
|
||||||
|
|
||||||
globalLinks[globalPageNumber][label] = {
|
|
||||||
tokens : this.lexer.blockTokens(content),
|
|
||||||
content : content,
|
|
||||||
href : href,
|
|
||||||
title : title
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
type : 'refLinkBlockDef',
|
|
||||||
raw : match[0],
|
|
||||||
tokens : this.lexer.blockTokens(content),
|
|
||||||
label : label,
|
|
||||||
href : href,
|
|
||||||
title : title
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
renderer(token){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const consumeBlockCall = {
|
|
||||||
name : 'consumeBlockCall',
|
|
||||||
level : 'block',
|
|
||||||
start(src) {return src.match(/^[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]/m)?.index; },
|
|
||||||
tokenizer(src, tokens) {
|
|
||||||
// [ variable name (spaces allowed) ] if only this and whitespace, parse var contents as block, else as inline
|
|
||||||
const regex = /^[!$]?\[((?!\s*\])(?:\\.|[^\[\]\\])+)\][ \t]*(?=\n|$)/;
|
|
||||||
const match = regex.exec(src);
|
|
||||||
if(match) {
|
|
||||||
return {
|
|
||||||
type : 'consumeBlockCall',
|
|
||||||
raw : match[0],
|
|
||||||
tokens : this.lexer.inline(`\n${match[0]}`), //Append \n so refLinkCall can distinguish between block and inline
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
renderer(token){
|
|
||||||
return this.parser.parseInline(token.tokens);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const refLinkCall = {
|
|
||||||
name : 'refLinkCall',
|
|
||||||
level : 'inline',
|
|
||||||
start(src) {return src.match(/\n?[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]/m)?.index;},
|
|
||||||
tokenizer(src, tokens) {
|
|
||||||
// [ variable name (spaces allowed) ]: Any text, including into newlines (but no fully blank lines)
|
|
||||||
const regex = /^\n?([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]/;
|
|
||||||
const match = regex.exec(src);
|
|
||||||
if(match) {
|
|
||||||
const label = match[2] ? match[2].trim().toLowerCase().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
|
||||||
|
|
||||||
const variable = lookupVar(label, globalPageNumber);
|
|
||||||
|
|
||||||
if (variable == undefined)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let tokens;
|
|
||||||
let block;
|
|
||||||
|
|
||||||
if(match[0][0] == '\n') {
|
|
||||||
block = true;
|
|
||||||
tokens = this.lexer.blockTokens(variable.content);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
block = false;
|
|
||||||
tokens = this.lexer.inlineTokens(variable.content);
|
|
||||||
}
|
|
||||||
|
|
||||||
let format = "link";
|
|
||||||
if(match[1] == "!")
|
|
||||||
format = "image";
|
|
||||||
if(match[1] == "$")
|
|
||||||
format = "variable";
|
|
||||||
|
|
||||||
return {
|
|
||||||
type : 'refLinkCall',
|
|
||||||
label : label,
|
|
||||||
raw : match[0],
|
|
||||||
tokens : tokens,
|
|
||||||
href : variable.href,
|
|
||||||
title : variable.title,
|
|
||||||
block : block,
|
|
||||||
format : format
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
renderer(token){
|
|
||||||
if(token.format == "link" && token.href) {
|
|
||||||
return `<a href="${token.href}"${token.title ? ` title="${token.title}"` : ''}>${token.label}</a>`;
|
|
||||||
}
|
|
||||||
if(token.format == "image" && token.href) {
|
|
||||||
return `<img src="${token.href}"${token.title ? ` title="${token.title}"` : ''}alt="${token.label}"/>`;
|
|
||||||
}
|
|
||||||
if(token.format == "variable") {
|
|
||||||
if(token.block)
|
|
||||||
return this.parser.parse(token.tokens);
|
|
||||||
else
|
|
||||||
return this.parser.parseInline(token.tokens);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const refLinkInlineDef = {
|
|
||||||
name : 'refLinkInlineDef',
|
|
||||||
level : 'inline',
|
|
||||||
start(src) {return src.match(/\n?[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]:\(.*\)/m)?.index;},
|
|
||||||
tokenizer(src, tokens) {
|
|
||||||
// [ variable name (spaces allowed) ]: Any text, including into newlines (but no fully blank lines)
|
|
||||||
const regex = /^\n?([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]:\((.*)\)/;
|
|
||||||
const match = regex.exec(src);
|
|
||||||
if(match) {
|
|
||||||
const label = match[2] ? match[2].trim().toLowerCase().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
|
||||||
const content = match[3] ? match[3].trim().toLowerCase().replace(/[ \t]+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
|
||||||
|
|
||||||
// url or <url> "title" or 'title' or (title)
|
|
||||||
const linkRegex = /^([^<\s][^\s]*|<.*?>)(?: ("(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\((?:\\\(|\\\)|[^()])*\)))?$/m
|
|
||||||
const linkMatch = linkRegex.exec(content);
|
|
||||||
|
|
||||||
let href = null;
|
|
||||||
let title = null;
|
|
||||||
if(linkMatch) {
|
|
||||||
href = linkMatch[1];
|
|
||||||
title = linkMatch[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!globalLinks[globalPageNumber])
|
|
||||||
globalLinks[globalPageNumber] = {};
|
|
||||||
|
|
||||||
globalLinks[globalPageNumber][label] = {
|
|
||||||
tokens : this.lexer.blockTokens(content),
|
|
||||||
content : content,
|
|
||||||
href : href,
|
|
||||||
title : title
|
|
||||||
}
|
|
||||||
|
|
||||||
const variable = lookupVar(label, globalPageNumber);
|
|
||||||
|
|
||||||
if (variable == undefined)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const tokens = this.lexer.inlineTokens(variable.content);
|
|
||||||
|
|
||||||
let format = "link";
|
|
||||||
if(match[1] == "!")
|
|
||||||
format = "image";
|
|
||||||
if(match[1] == "$")
|
|
||||||
format = "variable";
|
|
||||||
|
|
||||||
return {
|
|
||||||
type : 'refLinkCall',
|
|
||||||
label : label,
|
|
||||||
raw : match[0],
|
|
||||||
tokens : tokens,
|
|
||||||
href : variable.href,
|
|
||||||
title : variable.title,
|
|
||||||
block : false,
|
|
||||||
format : format
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
renderer(token){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const refLinkInlineNoDef = {
|
|
||||||
name : 'refLinkInlineNoDef',
|
|
||||||
level : 'inline',
|
|
||||||
start(src) {return src.match(/[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]\(.*\)/m)?.index; },
|
|
||||||
tokenizer(src, tokens) {
|
|
||||||
// [ variable name (spaces allowed) ]: Any text, including into newlines (but no fully blank lines)
|
|
||||||
const regex = /^([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]\((.*)\)/;
|
|
||||||
const match = regex.exec(src);
|
|
||||||
if(match) {
|
|
||||||
const label = match[2] ? match[2].trim().toLowerCase().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
|
||||||
const content = match[3] ? match[3].trim().toLowerCase().replace(/[ \t]+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
|
||||||
|
|
||||||
// url or <url> "title" or 'title' or (title)
|
|
||||||
const linkRegex = /^([^<\s][^\s]*|<.*?>)(?: ("(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\((?:\\\(|\\\)|[^()])*\)))?$/m
|
|
||||||
const linkMatch = linkRegex.exec(content);
|
|
||||||
|
|
||||||
let href = null;
|
|
||||||
let title = null;
|
|
||||||
if(linkMatch) {
|
|
||||||
href = linkMatch[1];
|
|
||||||
title = linkMatch[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
const tokens = this.lexer.inlineTokens(content);
|
|
||||||
|
|
||||||
let format = "link";
|
|
||||||
if(match[1] == "!")
|
|
||||||
format = "image";
|
|
||||||
if(match[1] == "$")
|
|
||||||
format = "variable";
|
|
||||||
|
|
||||||
return {
|
|
||||||
type : 'refLinkCall',
|
|
||||||
label : label,
|
|
||||||
raw : match[0],
|
|
||||||
tokens : tokens,
|
|
||||||
href : href,
|
|
||||||
title : title,
|
|
||||||
block : false,
|
|
||||||
format : format
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
renderer(token){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const lookupVar = function(label, index) {
|
|
||||||
if (globalLinks[index] === undefined) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (index >= 0) {
|
while (index >= 0) {
|
||||||
if (globalLinks[index][label] !== undefined) {
|
if(globalLinks[index]?.[label] !== undefined) {
|
||||||
return globalLinks[index][label];
|
return globalLinks[index][label];
|
||||||
}
|
}
|
||||||
index--;
|
index--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const generateVarToken = function(firstChar, label, content, href, title) {
|
const processVariableQueue = function() {
|
||||||
|
let resolvedOne = true;
|
||||||
|
let finalLoop = false;
|
||||||
|
let newQueue = [];
|
||||||
|
while (resolvedOne || finalLoop) { // Loop through queue until no more variable calls can be resolved
|
||||||
|
newQueue = [];
|
||||||
|
resolvedOne = false;
|
||||||
|
for (const item of linksQueue) {
|
||||||
|
const value = replaceVar(item.match, true);
|
||||||
|
|
||||||
// if(firstChar == "$") {
|
if(value.missingValues.length > 0 && !finalLoop) { // Variable not found; try again next loop.
|
||||||
// return {
|
newQueue.push(item); // If previous loops could not resolve any new vars,
|
||||||
// type : 'refLinkCall',
|
continue; // final loop will just use the best value so far
|
||||||
// label : label,
|
} // (may be only partially resolved)
|
||||||
// raw : match[0],
|
|
||||||
// tokens : tokens,
|
|
||||||
// href : href,
|
|
||||||
// title : title,
|
|
||||||
// block : false,
|
|
||||||
// format : "variable"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
resolvedOne = true;
|
||||||
|
|
||||||
// let format = "link";
|
item.token.content = item.token.content.replace(item.match, value.value);
|
||||||
// if(firstChar == "!")
|
|
||||||
// format = "image";
|
|
||||||
|
|
||||||
|
if(item.token.type == 'varDefBlock' || item.token.type == 'varDefInline') {
|
||||||
|
globalLinks[globalPageNumber][item.token.label] = {
|
||||||
|
content : item.token.content,
|
||||||
|
resolved : true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
linksQueue = newQueue;
|
||||||
|
if(finalLoop)
|
||||||
|
break;
|
||||||
|
if(!resolvedOne)
|
||||||
|
finalLoop = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const walkVariableTokens = {
|
||||||
|
walkTokens(token) {
|
||||||
|
if(token.type == 'varDefBlock' || token.type == 'varDefInline') {
|
||||||
|
|
||||||
// const tokens = this.lexer.inlineTokens(content);
|
const regex = /[!$]?\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]/g;
|
||||||
|
let match;
|
||||||
|
let resolved = true;
|
||||||
|
while (match = regex.exec(token.content)) { // regex to find variable calls
|
||||||
|
const value = replaceVar(match[0]);
|
||||||
|
|
||||||
// return {
|
if(value.missingValues.length > 0) {
|
||||||
// type : 'refLinkCall',
|
for (let i = 0; i < value.missingValues.length; i++) {
|
||||||
// label : label,
|
linksQueue.push({ token: token, match: match[0], varName: value.missingValues[i] });
|
||||||
// raw : match[0],
|
}
|
||||||
// tokens : tokens,
|
resolved = false;
|
||||||
// href : href,
|
} else {
|
||||||
// title : title,
|
token.content = token.content.replace(match[0], value.value);
|
||||||
// block : false,
|
}
|
||||||
// format : format
|
}
|
||||||
// }
|
|
||||||
|
globalLinks[globalPageNumber][token.label] = {
|
||||||
|
content : token.content,
|
||||||
|
resolved : resolved
|
||||||
|
};
|
||||||
|
if(token.type == 'varDefInline') //Inline definitions are also inline calls; after storing the value, change type so it can be displayed
|
||||||
|
token.type = 'varCallInline';
|
||||||
|
}
|
||||||
|
if(token.type == 'varCallBlock' || token.type == 'varCallInline' || token.originalType == 'varCallBlock' || token.originalType == 'varCallInline') {
|
||||||
|
const value = replaceVar(token.raw);
|
||||||
|
if(value.missingValues.length > 0) {
|
||||||
|
|
||||||
|
for (let i = 0; i < value.missingValues.length; i++) {
|
||||||
|
linksQueue.push({ token: token, match: token.raw, varName: value.missingValues[i] });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token.content = token.content.replace(token.content, value.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const varDefBlock = {
|
||||||
|
name : 'varDefBlock',
|
||||||
|
level : 'block',
|
||||||
|
start(src) {return src.match(/\n {0,3}[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]:/m)?.index; },
|
||||||
|
tokenizer(src, tokens) {
|
||||||
|
// [ variable name (spaces allowed) ]: Any text, including into newlines (but no fully blank lines)
|
||||||
|
const regex = /^ {0,3}[!$]?\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]:(?!\() *((?:\n? *[^\s].*)+)(?=\n+|$)/;
|
||||||
|
const match = regex.exec(src);
|
||||||
|
if(match) {
|
||||||
|
const label = match[1] ? match[1].trim().replace(/\s+/g, ' ').toLowerCase() : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
||||||
|
const content = match[2] ? match[2].trim().replace(/[ \t]+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
||||||
|
|
||||||
|
return {
|
||||||
|
type : 'varDefBlock',
|
||||||
|
raw : match[0],
|
||||||
|
label : label,
|
||||||
|
content : content
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderer(token){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const varDefInline = {
|
||||||
|
name : 'varDefInline',
|
||||||
|
level : 'inline',
|
||||||
|
start(src) {return src.match(/\n?[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]:\(.*\)/m)?.index;},
|
||||||
|
tokenizer(src, tokens) {
|
||||||
|
if(!parseVars) //Don't re-parse variable defs inside of another variable call
|
||||||
|
return;
|
||||||
|
// [ variable name (spaces allowed) ]: Any text, including into newlines (but no fully blank lines)
|
||||||
|
const regex = /^\n?([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\]:\((.*?)\)/;
|
||||||
|
const match = regex.exec(src);
|
||||||
|
if(match) {
|
||||||
|
const label = match[2] ? match[2].trim().toLowerCase().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
||||||
|
const content = match[3] ? match[3].trim().toLowerCase().replace(/\s+/g, ' ') : null; // Trim edge spaces and shorten blocks of whitespace to 1 space
|
||||||
|
|
||||||
|
return {
|
||||||
|
type : 'varDefInline',
|
||||||
|
raw : match[0],
|
||||||
|
label : label,
|
||||||
|
content : content
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderer(token) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const varCallBlock = {
|
||||||
|
name : 'varCallBlock',
|
||||||
|
level : 'block',
|
||||||
|
start(src) {return src.match(/\n[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]/m)?.index;},
|
||||||
|
tokenizer(src, tokens) {
|
||||||
|
if(!parseVars) //Don't re-parse variable calls inside of another variable call
|
||||||
|
return;
|
||||||
|
|
||||||
|
// [ variable name (spaces allowed) ] no following text allowed
|
||||||
|
const regex = /^([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\](?=\n|$)/;
|
||||||
|
const match = regex.exec(src);
|
||||||
|
if(match) {
|
||||||
|
return {
|
||||||
|
type : 'varCallBlock',
|
||||||
|
raw : match[0],
|
||||||
|
content : match[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderer(token){
|
||||||
|
const tokens = new Marked.Lexer(Marked.defaults).lex(token.content);
|
||||||
|
return this.parser.parse(tokens);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const varCallInline = {
|
||||||
|
name : 'varCallInline',
|
||||||
|
level : 'inline',
|
||||||
|
start(src) {return src.match(/[!$]?\[(?!\s*\])(?:\\.|[^\[\]\\])+\]/m)?.index;},
|
||||||
|
tokenizer(src, tokens) {
|
||||||
|
if(!parseVars) //Don't re-parse variable calls inside of another variable call
|
||||||
|
return;
|
||||||
|
|
||||||
|
// [ variable name (spaces allowed) ]: Any text, including into newlines (but no fully blank lines)
|
||||||
|
const regex = /^([!$]?)\[((?!\s*\])(?:\\.|[^\[\]\\])+)\](?!\()/; // Do not allow `(` after, since that is needed for normal images/links
|
||||||
|
const match = regex.exec(src);
|
||||||
|
if(match) {
|
||||||
|
return {
|
||||||
|
type : 'varCallInline',
|
||||||
|
raw : match[0],
|
||||||
|
content : match[0]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderer(token){
|
||||||
|
const tokens = new Marked.Lexer(Marked.defaults).inlineTokens(token.content);
|
||||||
|
return this.parser.parseInline(tokens);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
//^=====--------------------< Variable Handling >-------------------=====^//
|
//^=====--------------------< Variable Handling >-------------------=====^//
|
||||||
|
|
||||||
Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists, superSubScripts, refLinkCall, refLinkBlockDef, consumeBlockCall, refLinkInlineDef, refLinkInlineNoDef, consumeBlockDef]});
|
Marked.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists, superSubScripts, varCallInline, varDefInline, varCallBlock, varDefBlock] });
|
||||||
Marked.use(mustacheInjectBlock);
|
Marked.use(mustacheInjectBlock, walkVariableTokens);
|
||||||
Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false });
|
Marked.use({ renderer: renderer, tokenizer: tokenizer, mangle: false });
|
||||||
Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite());
|
Marked.use(MarkedExtendedTables(), MarkedGFMHeadingId(), MarkedSmartypantsLite());
|
||||||
|
|
||||||
@@ -693,22 +655,31 @@ const processStyleTags = (string)=>{
|
|||||||
`${attributes?.length ? ` ${attributes.join(' ')}` : ''}`;
|
`${attributes?.length ? ` ${attributes.join(' ')}` : ''}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
let globalLinks = {};
|
const globalLinks = {};
|
||||||
let globalPageNumber = 0;
|
let linksQueue = [];
|
||||||
|
let globalPageNumber = 0;
|
||||||
|
let parseVars = true;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
marked : Marked,
|
marked : Marked,
|
||||||
render : (rawBrewText, pageNumber=1)=>{
|
render : (rawBrewText, pageNumber=1)=>{
|
||||||
globalLinks[pageNumber] = {}; //Reset global links for current page, to ensure values are parsed in order
|
globalLinks[pageNumber] = {}; //Reset global links for current page, to ensure values are parsed in order
|
||||||
|
linksQueue = [];
|
||||||
globalPageNumber = pageNumber;
|
globalPageNumber = pageNumber;
|
||||||
|
|
||||||
|
parseVars = true;
|
||||||
|
|
||||||
rawBrewText = rawBrewText.replace(/^\\column$/gm, `\n<div class='columnSplit'></div>\n`)
|
rawBrewText = rawBrewText.replace(/^\\column$/gm, `\n<div class='columnSplit'></div>\n`)
|
||||||
.replace(/^(:+)$/gm, (match)=>`${`<div class='blank'></div>`.repeat(match.length)}\n`);
|
.replace(/^(:+)$/gm, (match)=>`${`<div class='blank'></div>`.repeat(match.length)}\n`);
|
||||||
const opts = Marked.defaults;
|
const opts = Marked.defaults;
|
||||||
|
|
||||||
rawBrewText = opts.hooks.preprocess(rawBrewText);
|
rawBrewText = opts.hooks.preprocess(rawBrewText);
|
||||||
const tokens = Marked.lexer(rawBrewText, opts);
|
const tokens = Marked.lexer(rawBrewText, opts);
|
||||||
|
|
||||||
Marked.walkTokens(tokens, opts.walkTokens);
|
Marked.walkTokens(tokens, opts.walkTokens);
|
||||||
|
processVariableQueue();
|
||||||
|
|
||||||
|
parseVars = false;
|
||||||
const html = Marked.parser(tokens, opts);
|
const html = Marked.parser(tokens, opts);
|
||||||
return opts.hooks.postprocess(html);
|
return opts.hooks.postprocess(html);
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user