diff --git a/packages/moon/dist/moon.js b/packages/moon/dist/moon.js index 1ade9e03..f5d9d469 100644 --- a/packages/moon/dist/moon.js +++ b/packages/moon/dist/moon.js @@ -89,11 +89,31 @@ */ var expressionRE = /"[^"]*"|'[^']*'|\d+[a-zA-Z$_]\w*|\.[a-zA-Z$_]\w*|[a-zA-Z$_]\w*:|([a-zA-Z$_]\w*)/g; + /** + * Capture special characters in text that need to be escaped. + */ + + var textRE = /&|>|<| |"|\\|"|\n|\r/g; /** * List of global variables to ignore in expression scoping */ var globals = ["NaN", "false", "in", "null", "this", "true", "typeof", "undefined", "window"]; + /** + * Map from special characters to a safe format for JavaScript string literals. + */ + + var escapeTextMap = { + "&": "&", + ">": ">", + "<": "<", + " ": " ", + """: "\\\"", + "\\": "\\\\", + "\"": "\\\"", + "\n": "\\n", + "\r": "\\r" + }; /** * Checks if a given character is a quote. * @@ -104,6 +124,18 @@ function isQuote(_char) { return _char === "\"" || _char === "'"; } + /** + * Escape text to make it usable in a JavaScript string literal. + * + * @param {string} text + */ + + + function escapeText(text) { + return text.replace(textRE, function (match) { + return escapeTextMap[match]; + }); + } /** * Scope an expression to use variables within the `data` object. * @@ -340,7 +372,7 @@ type: "tagOpen", value: "text", attributes: { - "": "\"" + text + "\"" + "": "\"" + escapeText(text) + "\"" }, closed: true }); diff --git a/packages/moon/dist/moon.min.js b/packages/moon/dist/moon.min.js index 31f4c33a..00daf591 100644 --- a/packages/moon/dist/moon.min.js +++ b/packages/moon/dist/moon.min.js @@ -4,4 +4,4 @@ * Released under the MIT License * https://kbrsh.github.io/moon */ -!function(e,n){"undefined"==typeof module?e.Moon=n():module.exports=n()}(this,function(){"use strict";var b={element:0,text:1,component:2};var y,O=/^\s+$/,k=/<([\w\d-_]+)([^>]*?)(\/?)>/g,A=/\s*([\w\d-_:@]*)(?:=(?:("[^"]*"|'[^']*')|{([^{}]*)}))?/g,n=/"[^"]*"|'[^']*'|\d+[a-zA-Z$_]\w*|\.[a-zA-Z$_]\w*|[a-zA-Z$_]\w*:|([a-zA-Z$_]\w*)/g,t=["NaN","false","in","null","this","true","typeof","undefined","window"];function S(e){return e.replace(n,function(e,n){return void 0===n||"$"===n[0]||-1!==t.indexOf(n)?e:"data."+n})}function r(e){e=e.trim();for(var n=[],t=0;t",t+2),i=e.slice(t+2,o);0,n.push({type:"tagClose",value:i}),t=o+1;continue}if("!"===a&&"-"===e[t+2]&&"-"===e[t+3]){var u=e.indexOf("--\x3e",t+4);0,t=u+3;continue}k.lastIndex=t;var l=k.exec(e);0;for(var d=l[0],f=l[1],s=l[2],p=l[3],c={},v=void 0;null!==(v=A.exec(s));){var h=v[0],m=v[1],g=v[2],w=v[3];0===h.length?A.lastIndex+=1:(c[m]=void 0===w?void 0===g?'""':g:S(w),"@"===m[0]&&(c[m]="function($event){"+c[m]+"}"))}n.push({type:"tagOpen",value:f,attributes:c,closed:"/"===p}),t+=d.length}else if("{"===r){var b="";for(t+=1;t]*?)(\/?)>/g,S=/\s*([\w\d-_:@]*)(?:=(?:("[^"]*"|'[^']*')|{([^{}]*)}))?/g,n=/"[^"]*"|'[^']*'|\d+[a-zA-Z$_]\w*|\.[a-zA-Z$_]\w*|[a-zA-Z$_]\w*:|([a-zA-Z$_]\w*)/g,C=/&|>|<| |"|\\|"|\n|\r/g,t=["NaN","false","in","null","this","true","typeof","undefined","window"],P={"&":"&",">":">","<":"<"," ":" ",""":'\\"',"\\":"\\\\",'"':'\\"',"\n":"\\n","\r":"\\r"};function q(e){return e.replace(n,function(e,n){return void 0===n||"$"===n[0]||-1!==t.indexOf(n)?e:"data."+n})}function r(e){e=e.trim();for(var n,t=[],r=0;r",r+2),u=e.slice(r+2,i);0,t.push({type:"tagClose",value:u}),r=i+1;continue}if("!"===o&&"-"===e[r+2]&&"-"===e[r+3]){var l=e.indexOf("--\x3e",r+4);0,r=l+3;continue}A.lastIndex=r;var d=A.exec(e);0;for(var f=d[0],s=d[1],p=d[2],c=d[3],v={},h=void 0;null!==(h=S.exec(p));){var m=h[0],g=h[1],w=h[2],b=h[3];0===m.length?S.lastIndex+=1:(v[g]=void 0===b?void 0===w?'""':w:q(b),"@"===g[0]&&(v[g]="function($event){"+v[g]+"}"))}t.push({type:"tagOpen",value:s,attributes:v,closed:"/"===c}),r+=f.length}else if("{"===a){var y="";for(r+=1;r", + "<": "<", + " ": " ", + """: "\\\"", + "\\": "\\\\", + "\"": "\\\"", + "\n": "\\n", + "\r": "\\r" +}; + /** * Checks if a given character is a quote. * @@ -39,6 +59,15 @@ function isQuote(char) { return char === "\"" || char === "'"; } +/** + * Escape text to make it usable in a JavaScript string literal. + * + * @param {string} text + */ +function escapeText(text) { + return text.replace(textRE, (match) => escapeTextMap[match]); +} + /** * Scope an expression to use variables within the `data` object. * @@ -304,7 +333,7 @@ export function lex(input) { type: "tagOpen", value: "text", attributes: { - "": `"${text}"` + "": `"${escapeText(text)}"` }, closed: true });