From b869e48bfffaec42f73fdd80ff9a9bcb3467678e Mon Sep 17 00:00:00 2001 From: Conduitry Date: Fri, 4 Aug 2017 21:36:14 -0400 Subject: [PATCH] saner escaping/unescaping of `@` and `#` sigils --- src/generators/dom/Block.ts | 4 ++-- src/generators/dom/index.ts | 12 +++++++----- src/generators/server-side-rendering/index.ts | 16 +++++++--------- .../server-side-rendering/visitors/Component.ts | 3 ++- src/utils/stringify.ts | 4 +++- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/generators/dom/Block.ts b/src/generators/dom/Block.ts index 70323ae5cf..4c494de794 100644 --- a/src/generators/dom/Block.ts +++ b/src/generators/dom/Block.ts @@ -355,8 +355,8 @@ export default class Block { ${properties} }; } - `.replace(/(\\\\)?#(\w*)/g, (match, escaped, name) => { - return escaped ? match.slice(2) : this.alias(name); + `.replace(/(#+)(\w*)/g, (match: string, sigil: string, name: string) => { + return sigil === '#' ? this.alias(name) : sigil.slice(1) + name; }); } } diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index e2cbc4751c..4458a3f9d4 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -145,9 +145,12 @@ export default function dom( if (generator.stylesheet.hasStyles && options.css !== false) { const { css, cssMap } = generator.stylesheet.render(options.filename); - const textContent = stringify(options.dev ? + // special case: we only want to escape '@' and not '#', because at this point all we'll be unescaping is '@' + const textContent = JSON.stringify((options.dev ? `${css}\n/*# sourceMappingURL=${cssMap.toUrl()} */` : - css); + css).replace(/(@+)/g, (match: string) => { + return match + match[0]; + })); builder.addBlock(deindent` function @add_css () { @@ -281,9 +284,8 @@ export default function dom( let result = builder .toString() - .replace(/(\\\\)?([@#])(\w*)/g, (match: string, escaped: string, sigil: string, name: string) => { - if (escaped) return match.slice(2); - if (sigil !== '@') return match; + .replace(/(@+)(\w*)/g, (match: string, sigil: string, name: string) => { + if (sigil !== '@') return sigil.slice(1) + name; if (name in shared) { if (options.dev && `${name}Dev` in shared) name = `${name}Dev`; diff --git a/src/generators/server-side-rendering/index.ts b/src/generators/server-side-rendering/index.ts index 59f9701e7a..0f1771da7a 100644 --- a/src/generators/server-side-rendering/index.ts +++ b/src/generators/server-side-rendering/index.ts @@ -6,6 +6,7 @@ import preprocess from './preprocess'; import visit from './visit'; import { removeNode, removeObjectKey } from '../../utils/removeNode'; import { Parsed, Node, CompileOptions } from '../../interfaces'; +import { stringify } from '../../utils/stringify'; export class SsrGenerator extends Generator { bindings: string[]; @@ -93,7 +94,7 @@ export default function ssr( var ${name} = {}; - ${name}.filename = ${JSON.stringify(options.filename)}; + ${name}.filename = ${stringify(options.filename)}; ${name}.data = function () { return ${templateProperties.data ? `@template.data()` : `{}`}; @@ -133,8 +134,8 @@ export default function ssr( deindent` components.push({ filename: ${name}.filename, - css: ${JSON.stringify(css)}, - map: ${JSON.stringify(cssMap)} + css: ${stringify(css)}, + map: ${stringify(cssMap.toString())} }); `} @@ -169,7 +170,7 @@ export default function ssr( var escaped = { '"': '"', - "'": ''', + "'": '&##39;', '&': '&', '<': '<', '>': '>' @@ -178,11 +179,8 @@ export default function ssr( function __escape ( html ) { return String( html ).replace( /["'&<>]/g, match => escaped[ match ] ); } - `.replace(/(\\)?([@#])(\w*)/g, (match: string, escaped: string, sigil: string, name: string) => { - if (escaped) return match.slice(1); - if (sigil !== '@') return match; - - return generator.alias(name); + `.replace(/(@+|#+)(\w*)/g, (match: string, sigil: string, name: string) => { + return sigil === '@' ? generator.alias(name) : sigil.slice(1) + name; }); return generator.generate(result, options, { name, format }); diff --git a/src/generators/server-side-rendering/visitors/Component.ts b/src/generators/server-side-rendering/visitors/Component.ts index 75785d6ffd..0b04a13b11 100644 --- a/src/generators/server-side-rendering/visitors/Component.ts +++ b/src/generators/server-side-rendering/visitors/Component.ts @@ -5,6 +5,7 @@ import Block from '../Block'; import { Node } from '../../../interfaces'; import getObject from '../../../utils/getObject'; import getTailSnippet from '../../../utils/getTailSnippet'; +import { stringify } from '../../../utils/stringify'; export default function visitComponent( generator: SsrGenerator, @@ -41,7 +42,7 @@ export default function visitComponent( } else if (attribute.value.length === 1) { const chunk = attribute.value[0]; if (chunk.type === 'Text') { - value = isNaN(chunk.data) ? JSON.stringify(chunk.data) : chunk.data; + value = isNaN(chunk.data) ? stringify(chunk.data) : chunk.data; } else { const { snippet } = block.contextualise(chunk.expression); value = snippet; diff --git a/src/utils/stringify.ts b/src/utils/stringify.ts index c16ac7a937..de9f223d9a 100644 --- a/src/utils/stringify.ts +++ b/src/utils/stringify.ts @@ -3,5 +3,7 @@ export function stringify(data: string) { } export function escape(data: string) { - return data.replace(/([^\\@#])?([@#])/g, '$1\\$2'); + return data.replace(/(@+|#+)/g, (match: string) => { + return match + match[0]; + }); }