Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Can't interpolate Pug variables into a Vue directive #238

Closed
millerrafi opened this issue Jun 24, 2021 · 7 comments · Fixed by #239
Closed

Bug: Can't interpolate Pug variables into a Vue directive #238

millerrafi opened this issue Jun 24, 2021 · 7 comments · Fixed by #239
Assignees
Labels
type: bug Functionality that does not work as intended/expected

Comments

@millerrafi
Copy link

Info

Tool Version
Plugin v1.15.3
Prettier v2.3.1
Framework vue
Node v14.8.0
OS win

Prettier config

{
  "arrowParens": "avoid",
  "pugAttributeSeparator": "none",
  "pugEmptyAttributes": "all",
  "pugSingleQuote": false,
  "pugSortAttributes": "asc",
  "singleQuote": true,
  "trailingComma": "none"
}

Input

- var foo = 'foo';

div(:class=`{ 'foo': ${foo} }`)
  block

Output or Error

src\js\mixins\index.pug
[error] src\js\mixins\index.pug: Error: SyntaxError: Unexpected token, expected "," (1:10)
[error] > 1 | {'foo': ${foo}}
[error]     |          ^
[error]     at PugPrinter.build (C:\Users\Avi\Development\Courses\165_code_of_conduct\node_modules\@prettier\plugin-pug\dist\printer.js:106:23)

Additional Context

I am using Pug mixins to abstract the template for my Vue app. The mixins use template string interpolation to dynamically render Vue directives in the HTML, and then the HTML becomes the template for mounting the Vue app.

The template strings cause the plugin to error. The error only happens with Vue directives. For other attributes the template strings work fine.

@Shinigami92
Copy link
Member

Okay, I think the issue is somewhere around here

plugin-pug/src/printer.ts

Lines 871 to 875 in 931fe36

if (isMultilineInterpolation(val)) {
// do not reformat multiline strings surrounded by `
} else if (isVueVForWithOf(token.name, token.val)) {
val = this.formatDelegatePrettier(val, 'vue');
} else if (isVueExpression(token.name)) {

So I already try to detect multiline strings that uses backticks
This is not your case

Then it checks for v-for with of, also not your case
Then vue expression -> this is your case, BUT we have now a problem, cause the vue expression assumes valid vue expression syntax. But yours is not valid syntax cause suddenly there is a pug interpolation there and the prettier parser for vue cannot handle this.

So I think the best we can do here is to introduce a new if-else branch on line 873 (so between isMultilineInterpolation and isVueVForWithOf) and check for just isInterpolation (that will almost check for backticks like in isMultilineInterpolation but without the right hand side include \n check)

Then we need to find a good solution to format such code (or ignore formatting at all like with the multiline ones)

@Shinigami92 Shinigami92 self-assigned this Jun 24, 2021
@Shinigami92 Shinigami92 added the type: bug Functionality that does not work as intended/expected label Jun 24, 2021
@Shinigami92
Copy link
Member

Shinigami92 commented Jun 24, 2021

Please review https://github.com/prettier/plugin-pug/pull/239/files

And you can do me also a favor if you could check this branch out, use yarn link and test it with your local project in real world scenario

I'm a little bit afraid, that I just disabled to much so that things that potentially formatted previously doesn't format now anymore 🤔


So currently it's just: if surrounded by backticks and include ${ somewhere, then don't format at all

@millerrafi
Copy link
Author

Thank you very much, I'm happy to review and test locally but I won't be available until Sunday or Monday.

As for a solution, it would be amazing for my use case to format for example

:class=`{'foo':${foo}}`

as

:class=`{ 'foo': ${foo} }`

but i would not be surprised if that isn't feasible

@Shinigami92
Copy link
Member

Ah damned, that's not possible 🙁
Cause I just get e.g. {'foo':${foo}} as string
Then it sees:

{'foo':${foo}}
       ^~~~~~ Unexpected token

So it would assume it is json in js but then suddenly see a dollar sign where a dollar sign is not possible cause it expected e.g a string, number, other primitive or object/array

@Shinigami92
Copy link
Member

This will land in the upcoming release, but this could take some days and I think I will first create a beta with some other current PRs

@Shinigami92
Copy link
Member

Please try out the new beta v1.16.0-0 and report anything back 🙂

@millerrafi
Copy link
Author

Much better, thank you! My Pug has never been so pretty 😄

Sorry about testing, I didn't get a linked version working on the first try and didn't have time to troubleshoot it.

And BTW I have had some other problems that break my code. I may open some issues and feel free to close them if out of scope, in the meantime I'm using //- prettier-ignore for those cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug Functionality that does not work as intended/expected
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants