3.0.5
Vue 3 Template Explorer (credit: @ota-meshi)
Use two consecutive closing braces in a string, inside a template.
Correct parsing.
Vue template compilation error: Error parsing JavaScript expression: Unterminated string constant (1:5)
This will happen frequently when using something like ICU message formatting, as seen in the example at the URL above.
(initially reported @ https://github.com/vuejs/vue-eslint-parser/issues/94)
The Vue compiler is not a JavaScript compiler, and the state machine does not include the JavaScript syntax environment, otherwise it will be very complicated. This still doesn't work in Vue2, and I think it can be solved by configuring delimiters.
it will be very complicated
yes, it's very complicated to determine which is the end tag in this case.
function parseInterpolation(
context: ParserContext,
mode: TextModes
): InterpolationNode | undefined {
const [open, close] = context.options.delimiters
__TEST__ && assert(startsWith(context.source, open))
// it's very complicated to determine which is the end tag.
const closeIndex = context.source.indexOf(close, open.length)
if (closeIndex === -1) {
emitError(context, ErrorCodes.X_MISSING_INTERPOLATION_END)
return undefined
}
Is there a way to escape?
Ah, just use the backslash to escape.
https://vue-next-template-explorer.netlify.app/#%7B%22src%22%3A%22%20%20%3Cp%3E%7B%7B%20%24fm('%7BserverCount%2C%20plural%2C%20one%20%7BServer%7D%20other%20%7BServers%7D%5C%5C%7D')%20%7D%7D%3C%2Fp%3E%22%2C%22ssr%22%3Afalse%2C%22options%22%3A%7B%22mode%22%3A%22module%22%2C%22prefixIdentifiers%22%3Afalse%2C%22optimizeImports%22%3Afalse%2C%22hoistStatic%22%3Atrue%2C%22cacheHandlers%22%3Afalse%2C%22scopeId%22%3Anull%2C%22inline%22%3Afalse%2C%22ssrCssVars%22%3A%22%7B%20color%20%7D%22%2C%22bindingMetadata%22%3A%7B%22TestComponent%22%3A%22setup%22%2C%22foo%22%3A%22setup%22%2C%22bar%22%3A%22props%22%7D%2C%22optimizeBindings%22%3Afalse%7D%7D
hmm that's not escaping, that's just making invalid syntax. I can do the same with } } (space). With escaping, the AST text node is not supposed to contain the escape character.
Not the same, for example:
console.log('}\}') // '}}'
But the following is not:
console.log('} }') // '} }'
I think what @HcySunYang said makes sense and escaping them inside strings is the way to go. Especially because it's only needed when two curly braces are together
So how would u deal with this scenario?
<p>{{ someFn({ a: {b: 1}}) }}</p>
Not sure why this issue is already closed?
@posva Why are you closing this issue? This is a clear and obvious bug.
As @longlho stated, placing a backslash between the braces is _not_ escaping anything, it's just avoiding the issue by preventing two braces from being positioned next to each other.
Please reopen.
Oh yeah, those are very different from the original ones with a string only
I mean they have the same root cause :) and also IF there's a escape sequence it'd be nice to have double escaping as well.
Interpolation braces are parsed in same way as browser parses <script> tag, basically it terminates on first occurrence of closing sequence. For including }} in string use concatenation '}'+'}' and use block comment for other cases }/**/} (or consider extracting the expression as a method or computed property).
hmm I'm not sure I understand what you mean by Interpolation braces are parsed in same way as browser parses <script> tag, basically it terminates on first occurrence of closing sequence., any DSL has a way of escaping syntax token so reserved tokens can be used. For HTML it's the HTML entities. Escaping is fine, the point is that parser is supposed to unescape when it parses, which is not the case here. Otherwise this subjects to a whole slew of potential double escaping issues for users.
Now if the decision is to not provide escapes at all, which is fine, I think the action item is to highlight that in the doc properly, so related issues can be linked and not re-discovered.
Contents of interpolation braces is JavaScript, providing escape sequence means custom syntax which would break JS tools and IDE.
This should be documented though. cc @vuejs/docs
I think it'd be great if u guys can formalize a spec for vue template. I mean like EBNF-style spec rather than "everything inside {{ }} is a black box". I assume it can also be TypeScript/CoffeeScript in there?
Regarding breaking JS tools, as I mentioned, if u unescape before piping to JS parser (in the AST) it should work no?
I started writing spec (https://github.com/vuejs/docs-next/pull/729), it follows HTML spec like format.
Yes, we can unescape in AST but it will break eslint, typescript, babel vetur (pretty much everything). Parsing of interpolation braces is designed same as <script> parsing of HTML (e.g. https://jsfiddle.net/znck/L375htkg/).
So, can we close this now as we don't see a way to effienctly detect this?
I assume it can also be TypeScript/CoffeeScript in there?
As far as I know (and I could be wrong), it's limited to JavaScript.
So, can we close this now as we don't see a way to effienctly detect this?
HTML likely avoids attempting to parse the contents of script elements, because it could be any language (although it's most often JavaScript), and it should be possible to parse an HTML document without having access to one of many potential script parsers.
It's somewhat different for Vue templates though, because it only supports JavaScript. So, in theory, it _could_ ship a JS parser and parse the interpolations. Hitting an invalid token (}} or the currently defined closing delimiter) would signal the end of the interpolation. This could also be useful for other things, like checking for valid JS syntax, etc.
The benefits would have to be weighed against:
I'd be interested to know what Evan thinks about this.
If there is no interest, then I'm okay with this issue being closed (although it _would_ probably be a good idea to document this limitation).
like checking for valid JS syntax, etc.
I also thought of this and I found a library to check js syntax:https://github.com/jquery/esprima.
maybe you can get some inspiration from this library.
I think we can close this once the docs has been updated since that seems to be the consensus for the action item here (so we can link from the formatjs side as well).
That's rather bad and closing doesn't feel like the right thing to do to me.
AFAIK:
compiler-sfc already embeds a JS parser, namely Babel.So when encountering a {{ interpolation marker, why not parse a JS expression starting on next char, then check if the expression is properly closed with }} and throw an error if the JS is invalid or the interpolation is not properly closed.
Sure, it's more work then doing a find for the next "}}" in string, but it's the right thing to do.
} can appear in many places inside a JS expression: inside comments /* }} */, strings "}}", interpolated strings `object is {${ obj }}`, object literals { a: { b: 4 }}, lambda or method member bodies function () { return () => { return { g() { }}}
If you don't want to parse, another common strategy when embedding DSL like that is to provide an escaping.
Tell people that if they need to write }} inside an interpolation they need to escape it somehow (and don't forget to provide an escape for the escape itself).
As others have mentioned in this thread, it impacts every tooling that needs to unescape the interpolated expression before processing it, so it isn't the best solution.
Just saying "find a way to write your code without }}" is the worst solution from a user perspective.
That's essentially what I suggested above, although I wasn't aware that the compiler already included Babel, which makes this even more feasible. It's probably worth reconsidering.
Most helpful comment
So how would u deal with this scenario?
Not sure why this issue is already closed?