Skip to content

Fix unstable embedded template literals#13532

Merged
thorn0 merged 16 commits intoprettier:nextfrom
thorn0:issue-6150-unstable-tpl
Sep 26, 2022
Merged

Fix unstable embedded template literals#13532
thorn0 merged 16 commits intoprettier:nextfrom
thorn0:issue-6150-unstable-tpl

Conversation

@thorn0
Copy link
Copy Markdown
Member

@thorn0 thorn0 commented Sep 25, 2022

Description

Fixes #6150
Fixes #11205

Template literals with embedded languages are hugged now if they're the only argument and have leading and trailing whitespace. The idempotence issue has been fixed.

Checklist

  • I’ve added tests to confirm my change works.
  • (If changing the API or CLI) I’ve documented the changes I’ve made (in the docs/ directory).
  • (If the change is user-facing) I’ve added my changes to changelog_unreleased/*/XXXX.md file following changelog_unreleased/TEMPLATE.md.
  • I’ve read the contributing guidelines.

Try the playground for this PR

@thorn0 thorn0 marked this pull request as ready for review September 25, 2022 17:37
Comment on lines +23 to +25
foo(/* HTML */ `<!-- bar1 -->
bar
<!-- bar2 -->`);
Copy link
Copy Markdown
Member Author

@thorn0 thorn0 Sep 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this specific case hugging actually doesn't look good to me.
Probably, it'd make sense to distinguish between these two cases and do hugging only for the 2nd:

// 1
foo(
  /* HTML */ `<!-- bar1 -->
    bar
    <!-- bar2 -->`
);

// 2
foo(/* HTML */ `
  <!-- bar1 -->
  bar
  <!-- bar2 -->
`);

Thoughts on whether this makes sense and on how to implement this (I guess we'd need to somehow check if there is a line in front of the closing `)?

upd: I did this for HTML embeds

@thorn0 thorn0 marked this pull request as draft September 25, 2022 18:09
@thorn0 thorn0 marked this pull request as ready for review September 26, 2022 06:33
@thorn0
Copy link
Copy Markdown
Member Author

thorn0 commented Sep 26, 2022

Using substrings in label checks instead of what clearly should be a list looks clumsy. It'd be more clear to extend the type of label docs (see #11205), but I decided not to do that in this PR.

Comment thread src/language-js/embed/html.js Outdated
]
);

return linebreak ? resultDoc : label("[no-hug]", resultDoc);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

label seems not limited to string, how about

return label({hug: false}, ...)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll try that.

Comment thread src/document/builders.js

function label(label, contents) {
return { type: DOC_TYPE_LABEL, label, contents };
return label ? { type: DOC_TYPE_LABEL, label, contents } : contents;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the label has to be truthy?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For building code to be more compact. E.g.

label(
  typeof doc.label === "object" && { commented: true, ...doc.label },
  [leading, doc, trailing]
)

No need to create an intermediate variable for [leading, doc, trailing].

Copy link
Copy Markdown
Member

@fisker fisker Sep 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the doc.label is null, you can still spread in object expression, they result the same, 0, false, undefined, "" won't pass typeof check

If the doc.label is null, 0, false, undefined, "" , you can still spread, they result the same.

Copy link
Copy Markdown
Member Author

@thorn0 thorn0 Sep 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doc.label can't be null because the label builder doesn't accept falsy values. So this code adds a type: "label" doc wrapper only if doc is a label itself and its .label is an object. This way things like .label.embed and .label.hug are propagated. Otherwise there is nothing to propagate, so it returns [leading, doc, trailing] without wrapping.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confusing myself.... you want to use the code above? Then the deleted comment seems more correct.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, but the concat builder had more explicit intention than arrays too. I expect we're going to have more code like this (relying on propagated labels). It's good to be explicit in one-off scenarios, but not in something repeated.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a trade-off for explicitness, a conditionalLabel builder could be added, but I'm not convinced it's really needed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

concat is a removed thing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't block this, just thought it's unnecessary limitation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

concat is a removed thing

Right. But it was explicit. It's just another instance of the typical "DRY vs explicit" tradeoff.

Won't block this, just thought it's unnecessary limitation.

I saw a reusable pattern. I used it at least 3 times only in this PR and expect it to be used more. So I encapsulated it into the function.

@thorn0 thorn0 linked an issue Sep 26, 2022 that may be closed by this pull request
@thorn0
Copy link
Copy Markdown
Member Author

thorn0 commented Sep 26, 2022

Ouch! Sometimes it's not wrong to have more than one changelog file in 1 PR.

Run yarn lint:changelog
Duplicate files for #13532 found.
  - changelog_unreleased/api/13532.md
  - changelog_unreleased/javascript/13532.md
Error: Process completed with exit code 1.

@fisker
Copy link
Copy Markdown
Member

fisker commented Sep 26, 2022

not wrong to have more than one changelog file in 1 PR.

My idea is to prevent accidentally "copy file" instead of "move file". You can remove that check.

@thorn0 thorn0 linked an issue Sep 26, 2022 that may be closed by this pull request
@fisker
Copy link
Copy Markdown
Member

fisker commented Sep 26, 2022

Filename of those files shouldn't used when generating blog post. You can also update

const match = prFile.match(/^(\d{4,})\.md$/);
to allow 13532-2.md

@thorn0 thorn0 merged commit 6d4d011 into prettier:next Sep 26, 2022
@thorn0 thorn0 deleted the issue-6150-unstable-tpl branch September 26, 2022 13:24
medikoo pushed a commit to medikoo/prettier-elastic that referenced this pull request Feb 4, 2024
jared-hughes added a commit to jared-hughes/DesModder that referenced this pull request Mar 30, 2024
This is supposed to fix unstable embedded template literals.

Ref prettier/prettier#13532
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: expand on label builder Unstable template literals marked with /* HTML */ and /* GraphQL */

2 participants