Index: lib/snippets.js |
=================================================================== |
--- a/lib/snippets.js |
+++ b/lib/snippets.js |
@@ -18,16 +18,20 @@ |
"use strict"; |
/** |
* @fileOverview Snippets implementation. |
*/ |
const {Filter} = require("./filterClasses"); |
+const singleCharacterEscapes = new Map([ |
+ ["n", "\n"], ["r", "\r"], ["t", "\t"] |
+]); |
+ |
let filters = new Set(); |
/** |
* Container for snippet filters |
* @class |
*/ |
let Snippets = { |
/** |
@@ -70,8 +74,92 @@ |
if (filter.isActiveOnDomain(domain)) |
result.push(filter.script); |
} |
return result; |
} |
}; |
exports.Snippets = Snippets; |
+ |
+/** |
+ * Parses a script and returns a list of all its commands and their arguments |
+ * @param {string} script |
+ * @return {Array.<string[]>} |
+ */ |
+function parseScript(script) |
+{ |
+ let tree = []; |
+ |
+ // Whether the next character should be treated as an escape sequence. |
kzar
2018/07/12 10:30:37
I don't these new comments add much, and they are
Manish Jethani
2018/07/12 10:57:49
Well I'm glad you think so, because I don't like t
|
+ let escape = false; |
+ |
+ // Whether we are within a quoted sequence. |
+ let withinQuotes = false; |
+ |
+ // The Unicode code point following a "\u" |
+ let unicodeEscape = null; |
+ |
+ let call = []; |
+ let argument = ""; |
+ |
+ // The terminating semicolon for the last command is optional; we add one |
+ // here to make our loop consistent. |
+ for (let character of script.trim() + ";") |
+ { |
+ if (unicodeEscape != null) |
+ { |
+ unicodeEscape += character; |
+ |
+ if (unicodeEscape.length == 4) |
+ { |
+ // Consider the Unicode escape only if it parses as a valid code point. |
+ let codePoint = parseInt(unicodeEscape, 16); |
+ if (!isNaN(codePoint)) |
+ argument += String.fromCodePoint(codePoint); |
+ |
+ unicodeEscape = null; |
+ } |
+ } |
+ else if (escape) |
+ { |
+ escape = false; |
+ |
+ if (character == "u") |
+ unicodeEscape = ""; |
+ else |
+ argument += singleCharacterEscapes.get(character) || character; |
+ } |
+ else if (character == "\\") |
+ { |
+ escape = true; |
+ } |
+ else if (character == "'") |
+ { |
+ withinQuotes = !withinQuotes; |
kzar
2018/07/12 10:30:37
Nice, I think this variable name is an improvement
|
+ } |
+ // Normally a semicolon or a whitespace character marks the end of an |
+ // argument, but within quotes these characters are taken literally and |
+ // included in the argument. |
+ else if (withinQuotes || character != ";" && !/\s/u.test(character)) |
+ { |
+ argument += character; |
+ } |
+ else |
+ { |
+ if (argument) |
+ { |
+ call.push(argument); |
+ argument = ""; |
+ } |
+ |
+ if (character == ";" && call.length > 0) |
+ { |
+ tree.push(call); |
+ call = []; |
+ } |
+ } |
+ } |
+ |
+ return tree; |
+} |
+ |
+exports.parseScript = parseScript; |