Skip to content

fix(js): protect ASI for conditional expressions under experimentalTernaries - #19923

Open
koding88 wants to merge 3 commits into
prettier:mainfrom
koding88:fix/no-semi-experimental-ternary-asi
Open

fix(js): protect ASI for conditional expressions under experimentalTernaries#19923
koding88 wants to merge 3 commits into
prettier:mainfrom
koding88:fix/no-semi-experimental-ternary-asi

Conversation

@koding88

Copy link
Copy Markdown

Fixes #18965

Summary

Adds ConditionalExpression to expressionNeedsAsiProtection() when experimentalTernaries is enabled, preventing dangerous semicolon omission before parenthesized multiline ternary conditions under --no-semi.

Background

Under experimentalTernaries, multiline ternary conditions are enclosed in parentheses via wrapInParens(print("test")). When combined with --no-semi, the leading ( of a multiline ternary expression statement requires a leading semicolon to prevent unintended function invocation with the preceding statement:

let o = 1;
(
    1 ||
    12345678901234567890123456789012345678901234567890123456789012345678901234567890
) ?
    2
:   3

Previously, expressionNeedsAsiProtection() did not handle ConditionalExpression, resulting in the omitted semicolon and a runtime TypeError: 1 is not a function. Adding ConditionalExpression when options.experimentalTernaries is set ensures the leading semicolon is correctly inserted.

Verification

  • yarn jest tests/format/js/ternaries/issue-18965/format.test.js: pass.
  • yarn test tests/format/js/conditional/ tests/format/js/no-semi/: pass.
  • yarn test: 35,272 tests passed (1,557 suites, 0 regressions).
  • yarn lint:prettier: clean.

Copilot AI lite review requested due to automatic review settings August 26, 2026 07:13
@netlify

netlify Bot commented Aug 26, 2026

Copy link
Copy Markdown

Deploy Preview for prettier ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 7a0c1d7
🔍 Latest deploy log https://app.netlify.com/projects/prettier/deploys/6a8e92003c9f5e00080503ef
😎 Deploy Preview https://deploy-preview-19923--prettier.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a JavaScript ASI (automatic semicolon insertion) hazard when experimentalTernaries is enabled and --no-semi is used, ensuring Prettier inserts a leading semicolon before parenthesized multiline ternary conditions so runtime semantics aren’t changed.

Changes:

  • Treat ConditionalExpression as needing ASI protection when options.experimentalTernaries is enabled.
  • Add a regression test + snapshot covering the --no-semi + experimentalTernaries multiline ternary condition case (issue #18965).
  • Add an unreleased changelog entry documenting the fix.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/format/js/ternaries/issue-18965/issue-18965.js Adds a minimal reproduction input for the ASI hazard scenario.
tests/format/js/ternaries/issue-18965/format.test.js Adds a format test enabling experimentalTernaries with semi: false.
tests/format/js/ternaries/issue-18965/snapshots/format.test.js.snap Verifies the output now includes the leading ;( under --no-semi.
src/language-js/semicolon/semicolon.js Ensures ConditionalExpression gets leading semicolon protection under experimentalTernaries.
changelog_unreleased/javascript/19923.md Documents the bug and the corrected output in the unreleased changelog.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@netlify

netlify Bot commented Aug 26, 2026

Copy link
Copy Markdown

Deploy Preview for prettier ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 82984c8
🔍 Latest deploy log https://app.netlify.com/projects/prettier/deploys/6a8fed4e038a660008009e83
😎 Deploy Preview https://deploy-preview-19923--prettier.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@fisker fisker left a comment

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.

Prettier PR #19923
Playground link

--parser babel
--no-semi
--experimental-ternaries

Input:

let o = 1;
a ?
   b
:   c

Output:

let o = 1
;a ? b : c

The static ConditionalExpression case in expressionNeedsAsiProtection
added a leading semicolon to every ternary expression statement under
experimentalTernaries, even when the test group doesn't break and no
parentheses are printed (e.g. 'a ? b : c' became ';a ? b : c').

Instead, tie the leading semicolon to the same ifBreak as the wrapping
parenthesis around the test in printTernary, so the ';' and '(' always
appear together: break -> ';(...', fit -> no semicolon.
@koding88

Copy link
Copy Markdown
Author

The false positive came from handling ConditionalExpression statically in expressionNeedsAsiProtection(). I've reworked the fix (82984c8): the leading semicolon is now tied to the same ifBreak as the wrapping parens around the test in printTernary, so ; and ( always appear together — a ? b : c no longer gets a leading semicolon, while a breaking test still prints ;(. Full test suite (35,285 tests) passes.

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.

Long condition with experimental-ternaries and no-semi deletes critical semicolon

3 participants