UNPKG

estilo

Version:

Create color schemes for Vim, NeoVim, Airline and Lightline

161 lines (160 loc) 6.53 kB
import { ParseErr } from "./err.js"; import { trimWS } from "./utils.js"; /* END TYPES */ const templateLitReg = /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})*}|(?!\${)[^\\`])*`/g; const singleQuoteReg = /'(?:\\[\s\w"'\\`]|[^\n\r'\\])*?'/g; const doubleQuoteReg = /"(?:\\[\s\w"'\\`]|[^\n\r"\\])*?"/g; /** Escape special regular expression characters inside a string */ function escapeRegExp(string) { // From MDN return string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string } function getLineNo(str, index) { return str.slice(0, index).split("\n").length; } export function parse(str) { const config = this.config; let buffer = []; let trimLeftOfNextStr = false; let lastIndex = 0; const parseOptions = config.parse; if (config.plugins) { for (let i = 0; i < config.plugins.length; i++) { const plugin = config.plugins[i]; if (plugin.processTemplate) { str = plugin.processTemplate(str, config); } } } /* Adding for EJS compatibility */ if (config.rmWhitespace) { // Code taken directly from EJS // Have to use two separate replaces here as `^` and `$` operators don't // work well with `\r` and empty lines don't work well with the `m` flag. // Essentially, this replaces the whitespace at the beginning and end of // each line and removes multiple newlines. str = str.replace(/[\r\n]+/g, "\n").replace(/^\s+|\s+$/gm, ""); } /* End rmWhitespace option */ templateLitReg.lastIndex = 0; singleQuoteReg.lastIndex = 0; doubleQuoteReg.lastIndex = 0; function pushString(strng, shouldTrimRightOfString) { if (strng) { // if string is truthy it must be of type 'string' strng = trimWS(strng, config, trimLeftOfNextStr, // this will only be false on the first str, the next ones will be null or undefined shouldTrimRightOfString); if (strng) { // replace \ with \\, ' with \' // we're going to convert all CRLF to LF so it doesn't take more than one replace strng = strng.replace(/\\|'/g, "\\$&").replace(/\r\n|\n|\r/g, "\\n"); buffer.push(strng); } } } const prefixes = [ parseOptions.exec, parseOptions.interpolate, parseOptions.raw, ].reduce(function (accumulator, prefix) { if (accumulator && prefix) { return accumulator + "|" + escapeRegExp(prefix); } else if (prefix) { // accumulator is falsy return escapeRegExp(prefix); } else { // prefix and accumulator are both falsy return accumulator; } }, ""); const parseOpenReg = new RegExp(escapeRegExp(config.tags[0]) + "(-|_)?\\s*(" + prefixes + ")?\\s*", "g"); const parseCloseReg = new RegExp("'|\"|`|\\/\\*|(\\s*(-|_)?" + escapeRegExp(config.tags[1]) + ")", "g"); let m; while ((m = parseOpenReg.exec(str))) { const precedingString = str.slice(lastIndex, m.index); lastIndex = m[0].length + m.index; const wsLeft = m[1]; const prefix = m[2] || ""; // by default either ~, =, or empty pushString(precedingString, wsLeft); parseCloseReg.lastIndex = lastIndex; let closeTag; let currentObj = false; while ((closeTag = parseCloseReg.exec(str))) { if (closeTag[1]) { const content = str.slice(lastIndex, closeTag.index); parseOpenReg.lastIndex = lastIndex = parseCloseReg.lastIndex; trimLeftOfNextStr = closeTag[2]; const currentType = prefix === parseOptions.exec ? "e" : prefix === parseOptions.raw ? "r" : prefix === parseOptions.interpolate ? "i" : ""; currentObj = { t: currentType, val: content }; break; } else { const char = closeTag[0]; if (char === "/*") { const commentCloseInd = str.indexOf("*/", parseCloseReg.lastIndex); if (commentCloseInd === -1) { ParseErr("unclosed comment", str, closeTag.index); } parseCloseReg.lastIndex = commentCloseInd; } else if (char === "'") { singleQuoteReg.lastIndex = closeTag.index; const singleQuoteMatch = singleQuoteReg.exec(str); if (singleQuoteMatch) { parseCloseReg.lastIndex = singleQuoteReg.lastIndex; } else { ParseErr("unclosed string", str, closeTag.index); } } else if (char === '"') { doubleQuoteReg.lastIndex = closeTag.index; const doubleQuoteMatch = doubleQuoteReg.exec(str); if (doubleQuoteMatch) { parseCloseReg.lastIndex = doubleQuoteReg.lastIndex; } else { ParseErr("unclosed string", str, closeTag.index); } } else if (char === "`") { templateLitReg.lastIndex = closeTag.index; const templateLitMatch = templateLitReg.exec(str); if (templateLitMatch) { parseCloseReg.lastIndex = templateLitReg.lastIndex; } else { ParseErr("unclosed string", str, closeTag.index); } } } } if (currentObj) { if (config.debug) { currentObj.lineNo = getLineNo(str, m.index); } buffer.push(currentObj); } else { ParseErr("unclosed tag", str, m.index); } } pushString(str.slice(lastIndex, str.length), false); if (config.plugins) { for (let i = 0; i < config.plugins.length; i++) { const plugin = config.plugins[i]; if (plugin.processAST) { buffer = plugin.processAST(buffer, config); } } } return buffer; }