diff --git a/CLAUDE.md b/CLAUDE.md index d8195d335..d5d69a2b7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1298,6 +1298,8 @@ single owner of those widths. **Leading comments have one rule and one emitter.** A comment run *before* an item (a value, member, list element, or comma-separated item) is emitted by `Printer::push_leading_comment_run` (`printer/comments/mod.rs`), which implements prettier's `printLeadingComment` and picks the separator after each comment from the source around **that comment only**, never from where the item starts: **space** when nothing but spaces follow its `*/` (so a run the author glued stays glued — `/* a */ /* b */⏎X`), a soft **`line`** when a newline follows but none precedes, and a blank-preserving **`hardline`** for an own-line block or any line comment. The glue test alone is `Printer::comment_hugs_next` — the single statement of the rule, called even by the few sites whose surrounding loop must differ (a separator policy of their own). ⚠️ Do not hand-roll `is_block && is_same_line(c.span.end, X)` at a new site: keying the hug on the *item* rather than on *what follows the comment* splits an author-glued run, and was a whole bug family (unglue / block-run merge). A site that also owns a comma emits the gap via `push_inter_item_line_comment_gap`, which owns the break too — that is what lets the last comment hug the next item. +**Whether that soft `line` collapses is decided by one fact, and it predicts every list site.** The **array family** — array literals, array patterns, and tuple types — wraps each element's run *plus* the element in a per-element `group` (`Printer::build_list_element_group`), so the `line` is measured against that element alone and collapses (`/* c1 */ /* c2 */ a`) even while the list itself is broken. The **params family** — function / type-parameter / type-argument / call-argument lists — gives an element **no group of its own** (the width path is a bare `join([",", line])`; the comment-forced-multiline path is a hardline-joined list), so the identical `line` has nothing to be measured against but the enclosing broken group, and breaks (`/* c1 */ /* c2 */⏎a`). This mirrors prettier exactly: `printArrayElements` pushes `group(print())` per element and `print()` carries the leading comments (`print/array.js`), while `printFunctionParameters` / `printTypeParameters` / `print/call-arguments.js` do not. Don't re-derive it per site — and don't "fix" a params-family break by adding a group, or an array-family collapse by removing one. + Higher-fidelity models (attached comments, trivia tokens) may be needed for IDE/linter use cases. ## Dependencies diff --git a/benches/js/lib/divergence/patterns.ts b/benches/js/lib/divergence/patterns.ts index a285a2603..5703287e4 100644 --- a/benches/js/lib/divergence/patterns.ts +++ b/benches/js/lib/divergence/patterns.ts @@ -1837,7 +1837,7 @@ const fill_101_boundary: DivergencePattern = { languages: ['svelte', 'typescript', 'css'], conformance_sections: ['CSS: Layout', 'CSS: Values', 'Svelte/HTML', 'TypeScript'], fixtures: [ - 'css/comma_separated_greedy_fill_prettier_divergence', + 'css/values/lists/comma_separated_greedy_fill_prettier_divergence', 'css/values/lists/comma_space_separated_long_prettier_divergence', 'svelte/elements/inline_element_fill_long_prettier_divergence', 'svelte/elements/inline_component_fill_long_prettier_divergence', diff --git a/crates/tsv_svelte/src/lexer.rs b/crates/tsv_svelte/src/lexer.rs index a994900ee..6e4a2cce8 100644 --- a/crates/tsv_svelte/src/lexer.rs +++ b/crates/tsv_svelte/src/lexer.rs @@ -1,7 +1,7 @@ use std::fmt; use std::str::Chars; // Shared lexer-error constructor: used by the unterminated/unexpected sites in `next_token`. -use tsv_lang::{ParseError, lex_err}; +use tsv_lang::{ParseError, lex_err, source_scan}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TokenKind { @@ -134,6 +134,18 @@ impl<'a> Lexer<'a> { } } + /// Move the cursor to byte offset `pos`, which must be a char boundary at or after the + /// current position. Lets a scan delegate a span to a byte-level helper + /// (`tsv_lang::source_scan`) and resume lexing just past it, instead of re-walking the + /// span char by char through `advance`. + #[inline] + fn seek_to(&mut self, pos: usize) { + debug_assert!(pos >= self.position && self.source.is_char_boundary(pos)); + self.chars = self.source[pos..].chars(); + self.current = self.chars.next(); + self.position = pos; + } + /// Byte offset of the first non-whitespace char at or after the cursor, without /// consuming input. Whitespace matches `skip_whitespace` (`char::is_whitespace`), /// so a follow-up `skip_whitespace()` lands exactly here. @@ -271,71 +283,49 @@ impl<'a> Lexer<'a> { Ok(self.make_token(TokenKind::Equals, start)) } Some(quote @ '\'' | quote @ '"') => { - // String literal for attribute values - // Handle escape sequences AND embedded expression tags like {expr} - // Inside {}, quotes are part of JS strings, not attribute delimiters + // Quoted attribute value. Only two things matter here: the closing quote, + // and any `{expr}` tag — whose interior is JS, where the attribute's quote + // character is just an ordinary byte (`title="{a['\"']}"`). // - // NOTE: Similar brace/string tracking logic exists in parse_attribute_value() - // (attribute.rs). The lexer tokenizes the whole string; the parser later - // extracts Text and ExpressionTag parts from it. Both need to track JS - // string contexts to handle quotes correctly. + // The expression is skipped WHOLE via the shared trivia-aware brace + // matcher rather than re-lexed here. It already knows every construct in + // which a `}` or a quote is not code — nested braces, strings (escape + // aware), template literals including `${…}` interpolation, comments, and + // regex literals — so no delimiter buried in one can be mistaken for the + // end of the expression or of the attribute. Hand-tracking a subset of + // those is the "comment-aware delimiter scan" bug class (see + // `tsv_debug scan_audit`): this scan used to track braces and strings but + // not comments or regex, so `title="{/* ` */ b}"` and `title="{f(/"/)}"` + // desynced it and it ran to EOF — an over-rejection of Svelte-valid input. + // + // `parse_attribute_value` (attribute.rs) re-walks the same value to split + // it into Text and ExpressionTag parts, and reaches the same answer the + // same way (via `parse_expression_tag_at`); this is the tokenizing half. self.advance(); // consume opening quote - let mut brace_depth = 0; - let mut in_js_string = false; - let mut js_string_char = '\0'; - while let Some(ch) = self.current { - if in_js_string { - // Inside a JS string within {expr} - if ch == '\\' { - // Escape sequence in JS string - self.advance(); - if self.current.is_some() { - self.advance(); - } - } else if ch == js_string_char { - // End of JS string - in_js_string = false; - self.advance(); - } else { - self.advance(); - } - } else if brace_depth > 0 { - // Inside an expression tag {expr} - if ch == '\'' || ch == '"' || ch == '`' { - // Start of JS string - in_js_string = true; - js_string_char = ch; - self.advance(); - } else if ch == '{' { - brace_depth += 1; - self.advance(); - } else if ch == '}' { - brace_depth -= 1; - self.advance(); - } else { - self.advance(); - } - } else { - // Outside expression tags — attribute-value text. HTML/Svelte - // attribute values have NO backslash escapes (unlike a JS string - // inside `{expr}`, handled above), so `\` is a literal char: - // `a="{x}\"` closes at the `"` with value `{x}\`, matching - // Svelte's parser. Treating `\` as an escape here read `\"` as an - // escaped quote and ran past the close → "Unterminated string - // literal" (an over-rejection of valid Svelte; the `fuzz` gate). - if ch == quote { - self.advance(); // consume closing quote - return Ok(self.make_token(TokenKind::String, start)); - } else if ch == '{' { - // Start of expression tag - brace_depth = 1; - self.advance(); - } else { - self.advance(); - } + if ch == quote { + self.advance(); // consume closing quote + return Ok(self.make_token(TokenKind::String, start)); + } + if ch == '{' { + let Some(close) = source_scan::scan_to_matching_brace( + self.source.as_bytes(), + self.position + 1, + self.source.len(), + ) else { + break; // unterminated `{` — the value can't close + }; + self.seek_to(close + '}'.len_utf8()); + continue; } + // Attribute-value text. HTML/Svelte attribute values have NO backslash + // escapes (unlike a JS string inside `{expr}`, skipped above), so `\` + // is a literal char: `a="{x}\"` closes at the `"` with value `{x}\`, + // matching Svelte's parser. Treating `\` as an escape here read `\"` as + // an escaped quote and ran past the close → "Unterminated string + // literal" (an over-rejection of valid Svelte; the `fuzz` gate). + self.advance(); } // Unterminated string Err(lex_err("Unterminated string literal in template", start)) diff --git a/crates/tsv_ts/src/printer/comments/lists.rs b/crates/tsv_ts/src/printer/comments/lists.rs index 1aff8c9bf..1cec2dc9a 100644 --- a/crates/tsv_ts/src/printer/comments/lists.rs +++ b/crates/tsv_ts/src/printer/comments/lists.rs @@ -6,7 +6,7 @@ // comment splitting, inline-block comment runs, and comma emission in forced- // multiline lists. -use super::{CommentVec, Printer}; +use super::{CommentVec, LeadingGlue, Printer}; use crate::ast::internal; use tsv_lang::Span; use tsv_lang::comments_to_emit_in_range; @@ -45,25 +45,21 @@ impl<'a> Printer<'a> { } } - /// Build docs for leading comments in a forced-multiline context. + /// Build the leading-comment run over `[start, end)` for a list whose comments have + /// forced it multiline (tuples, type params/args, function-type params, unions, the + /// bracket-break shell, the broken cast). /// - /// Comments between `start` and `end` (where `end` is the element start): - /// - Block comments on the same line as the element: `/*content*/ ` (inline with trailing space) - /// - Block comments on their own line: `/*content*/` + hardline - /// - Line comments: `//content` + hardline (always on own line) + /// A thin adapter over the shared leading-comment emitter + /// ([`Printer::push_leading_comment_run`]), so the separator after each comment + /// follows prettier's `printLeadingComment` (space / soft `line` / hardline, keyed on + /// the source around *that* comment, never on where `end` is). /// - /// Used when expanding comments force multiline formatting (unions, tuples, etc.) - pub(crate) fn build_leading_comments_multiline(&self, start: u32, end: u32) -> DocBuf { - self.build_leading_comments_multiline_opt(start, end, None) - } - - /// Like `build_leading_comments_multiline`, but when `skip_delim` is `Some(pos)`, - /// comments sharing `pos`'s source line are skipped — they were already emitted - /// as a trailing prefix on the opening delimiter's line (see - /// `delimiter_line_comment_prefix`), so emitting them here too would duplicate - /// them. Pass the `Option` that `delimiter_line_comment_prefix` returns - /// (gated to the first element of the list; `None` for the rest). - pub(in crate::printer) fn build_leading_comments_multiline_opt( + /// `skip_delim` drops the comments sharing `pos`'s source line: they were already + /// emitted as a trailing prefix on the opening delimiter's line (see + /// [`Self::delimiter_line_comment_prefix`]), so emitting them here too would + /// **duplicate** them. Pass the `Option` that helper returns — gated to the list's + /// first element, `None` for the rest, and `None` where no delimiter is involved. + pub(in crate::printer) fn build_leading_comments_multiline( &self, start: u32, end: u32, @@ -71,23 +67,69 @@ impl<'a> Printer<'a> { ) -> DocBuf { let d = self.d(); let mut parts = DocBuf::new(); - let mut comments = comments_to_emit_in_range(self.comments, start, end) - .filter(|c| !skip_delim.is_some_and(|pos| self.comment_on_delimiter_line(pos, c))) - .peekable(); - while let Some(comment) = comments.next() { - parts.push(self.build_comment_doc(comment)); - if self.comment_hugs_next(comment, end) { - parts.push(d.text(" ")); - } else { - // Preserve a blank line the author left between this comment and what - // follows it (the next own-line comment, or the element at `end`). - let next = comments.peek().map_or(end, |c| c.span.start); - self.push_blank_preserving_hardline(&mut parts, comment.span.end, next); - } - } + self.push_leading_comment_run( + &mut parts, + comments_to_emit_in_range(self.comments, start, end) + .filter(|c| !skip_delim.is_some_and(|pos| self.comment_on_delimiter_line(pos, c))), + end, + LeadingGlue::Adjacent, + d.empty(), + ); parts } + /// Assemble one **element** of an array-like list: its leading-comment run plus the + /// element, wrapped in a single `group`. + /// + /// The group is what lets a leading comment's soft `line` (prettier's + /// `printLeadingComment`) be measured against *this element alone* and collapse + /// (`/* c1 */ /* c2 */ a`) even though the list itself is broken. Prettier's + /// `printArrayElements` (`src/language-js/print/array.js`) does the same — it pushes + /// `group(print())` per element and `print()` carries the element's leading comments — + /// and array literals, array patterns, and tuple types all route through it. A line + /// comment (or an author blank line) in the run puts a `hardline` inside the group, so + /// it breaks and the element drops below, also matching prettier. + /// + /// This grouping is what separates the array family from the params family: function / + /// type-parameter / type-argument / call-argument lists use a bare `join([",", line])` + /// with **no** per-element group, so the identical soft `line` rides the broken outer + /// group and breaks. That one fact predicts the layout at every one of those sites — + /// don't re-derive it. See conformance_prettier.md §Comment relocation. + /// + /// A list with holes passes only its real elements here; a hole carries no comments and + /// takes no group. + pub(crate) fn build_list_element_group(&self, mut leading: DocBuf, element: DocId) -> DocId { + let d = self.d(); + leading.push(element); + d.group(d.concat(&leading)) + } + + /// [`Self::build_list_element_group`] for a caller holding the element's leading + /// comments as a list rather than a range — the array literal and array pattern, whose + /// per-element filter (which same-line block comments trail the *previous* element + /// across its comma) is too specific to express as a range. + /// + /// Builds the run here so the separator policy every array-family element shares + /// (`LeadingGlue::Adjacent`, no continuation indent) is stated once rather than at each + /// call. The range-holding sibling is + /// [`Self::build_leading_comments_multiline`]. + pub(crate) fn build_list_element_group_from_comments<'c>( + &self, + comments: impl Iterator, + element_start: u32, + element: DocId, + ) -> DocId { + let mut leading = DocBuf::new(); + self.push_leading_comment_run( + &mut leading, + comments, + element_start, + LeadingGlue::Adjacent, + self.d().empty(), + ); + self.build_list_element_group(leading, element) + } + /// Build docs for trailing comments in a forced-multiline context. /// /// Same-line comments (block or line): ` /*content*/` or ` //content` (inline with leading space) @@ -247,106 +289,80 @@ impl<'a> Printer<'a> { docs } - /// Build docs for leading comments before a node with blank line preservation. + /// Build the leading-comment run before `target_start` — the member, statement, or + /// element the comments lead. /// - /// Handles comments that appear before a member/statement, preserving blank lines - /// between consecutive comments and after the last comment. Returns a Vec of docs - /// to append directly before the target node. + /// A thin adapter over the shared leading-comment emitter + /// ([`Printer::push_leading_comment_run`]), for the callers holding their run as a + /// slice rather than a range (each applies a per-site filter — dropping the previous + /// statement's same-line trailing comments, or the ones pulled onto the delimiter + /// line). The separator after each comment is prettier's `printLeadingComment` + /// (space / soft `line` / blank-preserving hardline), keyed on the source around + /// *that* comment. /// - /// Used by: class body members, block statement bodies, interface members, type literals. + /// Every caller is an already-broken context — an expanded pattern, a multiline + /// member prefix, a class/interface body, a statement list — so the soft `line` + /// renders as a break here. That is why this reads as "hardline between own-line + /// comments" at every site; it is the general rule landing in a broken group, not a + /// policy of its own. A caller that ever measures this run inside a group that can + /// *fit* gets prettier's collapse for free, which is the point of routing here. /// - /// `force_non_inline`: when true, the *last* comment never glues to - /// `target_start` (no trailing space, no trailing hardline) — used when - /// `target_start` doesn't correspond to a node that will actually be - /// printed next (e.g. comments orphaned by a dropped `EmptyStatement`). - /// The caller's own next emission supplies the separator hardline; only a - /// blank line, which that caller can't rediscover on its own, is still - /// recorded here (as a bare `literalline`, so the caller's hardline completes it). - pub(crate) fn build_leading_comments_with_blank_lines( + /// Used by: class body members, interface/enum members, block statement bodies, + /// type literals, expanded object patterns. The orphaned-comment sibling is + /// [`Self::build_orphaned_comment_run`]. + pub(crate) fn build_leading_comments_before( &self, comments: &[&internal::Comment], target_start: u32, - force_non_inline: bool, ) -> DocBuf { - if comments.is_empty() { - return DocBuf::new(); - } - - let d = self.d(); - - // Check if there's a blank line after the last comment - let has_blank_after_last_comment = comments - .last() - .is_some_and(|c| self.has_blank_line_between(c.span.end, target_start)); - - let mut docs = DocBuf::new(); - let mut last_pos = comments[0].span.start; - - for (j, comment) in comments.iter().enumerate() { - let is_last_comment = j == comments.len() - 1; - - // Check if there's a blank line after this comment - // (to next comment or to target if last comment) - let has_blank_after = if is_last_comment { - has_blank_after_last_comment - } else { - self.has_blank_line_between(comment.span.end, comments[j + 1].span.start) - }; - - // Check if the next item (comment or target) is on the same line as this comment's end. - // This handles multi-line block comments where the closing */ is followed by another - // comment on the same line: `/*\nmulti\n*/ /* after */` - let next_on_same_line = if is_last_comment { - self.is_same_line(comment.span.end, target_start) - } else { - self.is_same_line(comment.span.end, comments[j + 1].span.start) - }; - - // For subsequent comments, determine separator from previous comment - if j > 0 { - if self.is_same_line(last_pos, comment.span.start) { - // Same line as previous comment's end — keep inline (space is - // handled by the previous comment's suffix, so no space here) - } else if self.has_blank_line_between(last_pos, comment.span.start) { - docs.push(d.literalline()); - docs.push(d.hardline()); - } - // else: no separator needed (previous comment's suffix handled it) - } - - docs.push(self.build_comment_doc(comment)); - - if force_non_inline && is_last_comment { - // Nothing glues to `target_start` here — defer the separator - // to the caller's next emission. Only a blank line needs - // recording (the caller's own gap check starts later in the - // source and can't see it). - if has_blank_after { - docs.push(d.literalline()); - } - } else if !comment.is_block { - // Line comment: add hardline after unless there's a blank line after - // (the blank line separator will handle it) - if !has_blank_after { - docs.push(d.hardline()); - } - } else if next_on_same_line { - // Block comment on same line as next item - space before next - docs.push(d.text(" ")); - } else if !has_blank_after { - // Block comment on its own line: add hardline unless there's blank after - docs.push(d.hardline()); - } - last_pos = comment.span.end; - } + let mut parts = DocBuf::new(); + self.push_leading_comment_run( + &mut parts, + comments.iter().copied(), + target_start, + LeadingGlue::Adjacent, + self.d().empty(), + ); + parts + } - // Add blank line after last comment if present - if has_blank_after_last_comment && !force_non_inline { - docs.push(d.literalline()); - docs.push(d.hardline()); + /// Build the run for comments **orphaned by a dropped statement** — a bare `;` + /// (`EmptyStatement`) never prints in a body list, so the comments in its gap have + /// no node to lead. `gap_end` is a source position, not something that will be + /// emitted. + /// + /// So the last comment must not glue to `gap_end`, and takes no separator at all — + /// the caller's own next emission supplies it. Only an author blank line is recorded + /// (a bare `literalline`, which the caller's hardline completes), because the + /// caller's gap check starts later in the source and cannot rediscover it. + /// + /// Every *other* comment in the run leads the next comment, which is an ordinary + /// leading run — so it routes through the shared emitter unchanged, and only the + /// last comment is special-cased here. + /// + /// A sibling of [`Self::build_leading_comments_before`] rather than a flag on it: + /// what differs is not a separator policy but whether the run has a target at all. + pub(crate) fn build_orphaned_comment_run( + &self, + comments: &[&internal::Comment], + gap_end: u32, + ) -> DocBuf { + let mut parts = DocBuf::new(); + let Some((last, leading)) = comments.split_last() else { + return parts; + }; + self.push_leading_comment_run( + &mut parts, + leading.iter().copied(), + last.span.start, + LeadingGlue::Adjacent, + self.d().empty(), + ); + parts.push(self.build_comment_doc(last)); + if self.has_blank_line_between(last.span.end, gap_end) { + parts.push(self.d().literalline()); } - - docs + parts } /// Build docs for trailing comments at the end of a body (before closing `}`). @@ -467,7 +483,7 @@ impl<'a> Printer<'a> { let d = self.d(); let (line_prefix, pull_pos) = self.delimiter_line_comment_prefix(bracket_char, body_start); let mut inner = - self.build_leading_comments_multiline_opt(bracket_char + 1, body_start, pull_pos); + self.build_leading_comments_multiline(bracket_char + 1, body_start, pull_pos); inner.push(body); d.group_break(d.concat(&[ d.text(open), diff --git a/crates/tsv_ts/src/printer/comments/mod.rs b/crates/tsv_ts/src/printer/comments/mod.rs index 44e8152e6..9b9b5fa08 100644 --- a/crates/tsv_ts/src/printer/comments/mod.rs +++ b/crates/tsv_ts/src/printer/comments/mod.rs @@ -550,8 +550,23 @@ impl<'a> Printer<'a> { /// [`build_rhs_comments_opt`](Self::build_rhs_comments_opt), /// [`build_rhs_comments_glued_opt`](Self::build_rhs_comments_glued_opt), the /// arrow-body run, the member-leading sites (interface / intersection members), - /// and the comma-separated inter-item gaps (declarators, for-init, heritage, - /// switch cases). + /// the comma-separated inter-item gaps (declarators, for-init, heritage, + /// switch cases), the forced-multiline lists via + /// [`build_leading_comments_multiline`](Self::build_leading_comments_multiline) + /// (tuples, type params/args, function-type params, the union's first member, the + /// bracket-break shell, the broken `` cast), the array literal / array pattern + /// element runs, the body/member runs via + /// [`build_leading_comments_before`](Self::build_leading_comments_before) (class, + /// interface and enum members, statement lists, type literals, expanded object + /// patterns), and — for all but its last comment — + /// [`build_orphaned_comment_run`](Self::build_orphaned_comment_run). + /// + /// Three loops still emit a leading run themselves, because their surrounding + /// separator policy genuinely differs — the import/export specifier list, the + /// for-clause leading gap, and the union's inter-member run (which brackets the + /// `| ` separator and preserves blanks in different positions). Each calls + /// [`comment_hugs_next`](Self::comment_hugs_next) rather than re-deriving the rule, + /// so what differs there is the loop, never the decision. pub(crate) fn push_leading_comment_run<'c>( &self, parts: &mut DocBuf, diff --git a/crates/tsv_ts/src/printer/decorators.rs b/crates/tsv_ts/src/printer/decorators.rs index dce518e06..3c239c674 100644 --- a/crates/tsv_ts/src/printer/decorators.rs +++ b/crates/tsv_ts/src/printer/decorators.rs @@ -61,8 +61,8 @@ impl<'a> Printer<'a> { /// the same source line stay together with a space (`/* c1 */ /* c2 */`); every /// other boundary drops to its own line via a blank-preserving `hardline` — /// prettier's leading-comment separator rule (`printLeadingComment`), the same - /// rule `push_leading_comment_run` / `build_leading_comments_with_blank_lines` - /// apply for an undecorated member. Emits NO trailing separator toward the token: + /// rule `push_leading_comment_run` / `build_leading_comments_before` apply for an + /// undecorated member. Emits NO trailing separator toward the token: /// the decorator layout's own item-join / trailing break connects to it. Shared /// by all three decorator comment paths (class-level, member, parameter) so a /// same-line comment pair renders identically whether or not it decorates. diff --git a/crates/tsv_ts/src/printer/expressions/arrays.rs b/crates/tsv_ts/src/printer/expressions/arrays.rs index 9dd5a61f2..328694ecf 100644 --- a/crates/tsv_ts/src/printer/expressions/arrays.rs +++ b/crates/tsv_ts/src/printer/expressions/arrays.rs @@ -730,42 +730,14 @@ impl<'a> Printer<'a> { parts.push(d.hardline()); } - // Emit leading comments BEFORE real element. - if elem.is_some() { - for (ci, comment) in leading_comments.iter().enumerate() { - if ci > 0 { - let prev_comment_end = leading_comments[ci - 1].span.end; - if self.has_blank_line_between(prev_comment_end, comment.span.start) { - parts.push(d.literalline()); - parts.push(d.hardline()); - } - } - parts.push(self.build_comment_doc(comment)); - // If a blank line follows, the next iter's literalline+hardline - // handles the separator — emit nothing here. - let next_is_separated_by_blank = - leading_comments.get(ci + 1).is_some_and(|next| { - self.has_blank_line_between(comment.span.end, next.span.start) - }); - if !next_is_separated_by_blank { - if self.comment_hugs_next(comment, elem_start) { - parts.push(d.text(" ")); - } else { - // Last comment before the element: preserve a blank line - // the author left between the comment and the element. - if leading_comments.get(ci + 1).is_none() - && self.has_blank_line_between(comment.span.end, elem_start) - { - parts.push(d.literalline()); - } - parts.push(d.hardline()); - } - } - } - } - + // The element's leading run and the element form one group — see + // `build_list_element_group` for why. A hole takes neither. if let Some(e) = elem { - parts.push(self.build_arg_expression_doc(e)); + parts.push(self.build_list_element_group_from_comments( + leading_comments.iter().copied(), + elem_start, + self.build_arg_expression_doc(e), + )); } // Same-line trailing comments (real elements only). diff --git a/crates/tsv_ts/src/printer/expressions/blocks.rs b/crates/tsv_ts/src/printer/expressions/blocks.rs index fef99c549..3c881c403 100644 --- a/crates/tsv_ts/src/printer/expressions/blocks.rs +++ b/crates/tsv_ts/src/printer/expressions/blocks.rs @@ -300,11 +300,8 @@ impl<'a> Printer<'a> { } else if has_leading { body_parts.push(d.hardline()); } - body_parts.extend(self.build_leading_comments_with_blank_lines( - &leading_comments, - search_end, - true, - )); + body_parts + .extend(self.build_orphaned_comment_run(&leading_comments, search_end)); prev_stmt_end = Some(stmt_end); } @@ -338,7 +335,17 @@ impl<'a> Printer<'a> { // Check for blank lines between statements — up to the first comment // physically in the gap, which is not always the first one this gap // *emits* (an owned annotation is printed by the statement it leads). - let blank_line_check_end = self.blank_scan_end(prev_end, stmt_start); + // + // Inside the window gate: `blank_scan_end` is itself a comment search, + // and with no comment anywhere in the block it provably returns + // `stmt_start`. The gate is an *on-page* question and this is an + // *in-source* one, which is sound because only the *to-emit* axis skips + // an owned comment — on-page and in-source have the same membership. + let blank_line_check_end = if body_has_comments { + self.blank_scan_end(prev_end, stmt_start) + } else { + stmt_start + }; if self.has_blank_line_between(prev_end, blank_line_check_end) { body_parts.push(d.literalline()); } @@ -346,11 +353,7 @@ impl<'a> Printer<'a> { } // Print leading comments before this statement (with blank line preservation) - body_parts.extend(self.build_leading_comments_with_blank_lines( - &leading_comments, - stmt_start, - false, - )); + body_parts.extend(self.build_leading_comments_before(&leading_comments, stmt_start)); // format-ignore: emit raw source instead of formatting if body_has_comments && self.has_format_ignore_in_range(prev_end, stmt_start) { diff --git a/crates/tsv_ts/src/printer/expressions/mod.rs b/crates/tsv_ts/src/printer/expressions/mod.rs index 0cd8e93f7..25e6abf62 100644 --- a/crates/tsv_ts/src/printer/expressions/mod.rs +++ b/crates/tsv_ts/src/printer/expressions/mod.rs @@ -541,10 +541,17 @@ impl<'a> Printer<'a> { let angle_end = open_pos + 1; // after `<` let (angle_prefix, angle_pull_pos) = self.delimiter_line_comment_prefix(open_pos, type_start); - let leading = - self.build_leading_comments_multiline_opt(angle_end, type_start, angle_pull_pos); + let leading = self.build_leading_comments_multiline(angle_end, type_start, angle_pull_pos); let trailing = self.build_trailing_comments_multiline(type_end, close_angle); - d.concat(&[ + // `group_break`, not a bare concat: this is the already-broken form, and saying + // so contains the leading run's soft `line` (prettier's `printLeadingComment`) + // here rather than letting it escape to the enclosing assignment group — which + // would measure it against that group and wrongly pull the type up onto the + // comment's line. Prettier gives the cast no per-element group, so the `line` + // rides the broken group and breaks. The sibling angle/paren lists + // (type params, type args, function-type params) are already grouped by their + // own callers, which is why they land on the break without this. + d.group_break(d.concat(&[ d.text("<"), d.concat(&angle_prefix), d.indent(d.concat(&[ @@ -555,7 +562,7 @@ impl<'a> Printer<'a> { ])), d.hardline(), d.text(">"), - ]) + ])) } /// Build a Doc for a TypeScript binary cast expression — `expr as Type` or @@ -684,6 +691,16 @@ impl<'a> Printer<'a> { type_annotation: &TSType<'_>, type_start: u32, ) -> Option { + // The discriminant first: it is free, and the overwhelmingly common cast + // (`x as Foo`) is not a union — it paid a binary search only to learn that. + // Deliberately a guard here rather than moving the gap search below + // `build_union_hanging_indent_doc`: that function BUILDS the union doc before + // it can return, so a reorder would build-then-discard on a commented gap. + // This mirrors its own first check exactly (a bare match on the type, no paren + // unwrapping), so it only ever retires work the callee would redo. + if !matches!(type_annotation, TSType::Union(_)) { + return None; + } let keyword_len = keyword.len() as u32; if keyword_pos .is_some_and(|pos| self.has_comments_to_emit_between(pos + keyword_len, type_start)) @@ -710,15 +727,18 @@ impl<'a> Printer<'a> { type_annotation: &TSType<'_>, type_start: u32, ) -> Option { + // Discriminant before the gap search: it is free, and both checks only ever + // `return None`, so the order is unobservable. The overwhelmingly common cast + // (`x as Foo`) is not an intersection, and paid a binary search to learn it. + let TSType::Intersection(i) = type_annotation else { + return None; + }; let keyword_len = keyword.len() as u32; if keyword_pos .is_some_and(|pos| self.has_comments_to_emit_between(pos + keyword_len, type_start)) { return None; } - let TSType::Intersection(i) = type_annotation else { - return None; - }; let d = self.d(); let body = self.intersection_hanging_with_indent(i); Some(d.concat(&[d.text(" "), d.text(keyword), d.text(" "), body])) diff --git a/crates/tsv_ts/src/printer/expressions/patterns.rs b/crates/tsv_ts/src/printer/expressions/patterns.rs index 0a28426e0..849790fe9 100644 --- a/crates/tsv_ts/src/printer/expressions/patterns.rs +++ b/crates/tsv_ts/src/printer/expressions/patterns.rs @@ -610,11 +610,7 @@ impl<'a> Printer<'a> { CommentVec::new() }; - prop_parts.extend(self.build_leading_comments_with_blank_lines( - &leading_comments, - prop_start, - false, - )); + prop_parts.extend(self.build_leading_comments_before(&leading_comments, prop_start)); // A preceding format-ignore directive keeps the property's source verbatim // (trailing comment/comma handled normally) @@ -995,14 +991,15 @@ impl<'a> Printer<'a> { .is_some_and(|dpos| self.comment_on_delimiter_line(dpos, c))) }) .collect(); - parts.extend(self.build_leading_comments_with_blank_lines( - &leading_comments, + // The element's leading run and the element form one group — see + // `build_list_element_group` for why (prettier routes `ArrayPattern` + // through the same `printArray` as an array literal). + parts.push(self.build_list_element_group_from_comments( + leading_comments.iter().copied(), elem_start, - false, + self.build_expression_doc(e), )); - parts.push(self.build_expression_doc(e)); - let elem_end = e.span().end; // Collect trailing comments (stop at next element) diff --git a/crates/tsv_ts/src/printer/mod.rs b/crates/tsv_ts/src/printer/mod.rs index ffe85bcd8..aab6abd3c 100644 --- a/crates/tsv_ts/src/printer/mod.rs +++ b/crates/tsv_ts/src/printer/mod.rs @@ -60,7 +60,7 @@ pub(crate) use expressions::assignment::{ is_type_assertion_call, jsdoc_cast_comment_is_own_line, }; pub(crate) use needs_parens::{ParenContext, is_in_binary, needs_parens}; -pub(crate) use types::{should_hug_union_type, unwrap_parenthesized}; +pub(crate) use types::unwrap_parenthesized; use crate::PrinterInputs; use crate::ast::internal; diff --git a/crates/tsv_ts/src/printer/statements/class.rs b/crates/tsv_ts/src/printer/statements/class.rs index 5f3c313c2..78f6aadd0 100644 --- a/crates/tsv_ts/src/printer/statements/class.rs +++ b/crates/tsv_ts/src/printer/statements/class.rs @@ -306,11 +306,7 @@ impl<'a> Printer<'a> { } // Process comments before this member (with blank line preservation) - member_parts.extend(self.build_leading_comments_with_blank_lines( - &comments, - member_start, - false, - )); + member_parts.extend(self.build_leading_comments_before(&comments, member_start)); // A preceding format-ignore directive keeps the member's source verbatim. // The member span includes its trailing `;`. diff --git a/crates/tsv_ts/src/printer/statements/control_flow/switch.rs b/crates/tsv_ts/src/printer/statements/control_flow/switch.rs index f18c626cd..ed5ab4cd9 100644 --- a/crates/tsv_ts/src/printer/statements/control_flow/switch.rs +++ b/crates/tsv_ts/src/printer/statements/control_flow/switch.rs @@ -291,11 +291,8 @@ impl<'a> Printer<'a> { stmt_parts.push(d.hardline()); } } - stmt_parts.extend(self.build_leading_comments_with_blank_lines( - &leading_comments, - search_end, - true, - )); + stmt_parts + .extend(self.build_orphaned_comment_run(&leading_comments, search_end)); parts.push(d.indent(d.concat(&stmt_parts))); prev_stmt_end = Some(stmt_end); } diff --git a/crates/tsv_ts/src/printer/statements/mod.rs b/crates/tsv_ts/src/printer/statements/mod.rs index b148706a9..f710a38a4 100644 --- a/crates/tsv_ts/src/printer/statements/mod.rs +++ b/crates/tsv_ts/src/printer/statements/mod.rs @@ -16,9 +16,7 @@ mod type_declarations; mod variable; // Re-export for submodules to use `super::Printer` instead of `super::super::Printer` -pub(super) use super::{ - Printer, build_entity_name_doc, is_effectively_empty_body, should_hug_union_type, -}; +pub(super) use super::{Printer, build_entity_name_doc, is_effectively_empty_body}; use super::ParenContext; use super::class_expr_has_decorators; diff --git a/crates/tsv_ts/src/printer/statements/type_declarations.rs b/crates/tsv_ts/src/printer/statements/type_declarations.rs index 746fe4445..ebc329d53 100644 --- a/crates/tsv_ts/src/printer/statements/type_declarations.rs +++ b/crates/tsv_ts/src/printer/statements/type_declarations.rs @@ -1,7 +1,7 @@ // Type declaration printing (type aliases, interfaces, enums, namespaces, declare functions) // plus shared entity-name helpers -use super::{Printer, build_entity_name_doc, is_effectively_empty_body, should_hug_union_type}; +use super::{Printer, build_entity_name_doc, is_effectively_empty_body}; use crate::ast::internal::{self, TSType}; use crate::printer::layout::hang_after_operator; use crate::printer::{CommentFilter, CommentSpacing, CommentVec, HeritageKeyword, LeadingGlue}; @@ -301,7 +301,11 @@ impl<'a> Printer<'a> { // breaking from this context's group. if let TSType::Union(u) = value_type { let type_doc = self.build_union_type_doc(u); - if should_hug_union_type(u) { + // `union_prints_hugged`, not the bare syntactic `should_hug_union_type`: + // this must agree with the layout `build_union_type_doc` just chose. A + // comment can make it decline the hug and expand, and then the `=` has + // to break like any other non-hugging union. + if self.union_prints_hugged(u) { // Hugged unions (e.g., `{ ... } | null`): the object type handles its own // expansion, so keep `= {` together like other internally-breaking types parts.push(d.text(" ")); @@ -737,11 +741,7 @@ impl<'a> Printer<'a> { parts.push(d.hardline()); // Print leading comments with blank line preservation - parts.extend(self.build_leading_comments_with_blank_lines( - &leading_comments, - member_start, - false, - )); + parts.extend(self.build_leading_comments_before(&leading_comments, member_start)); // A preceding format-ignore directive keeps the member's source verbatim. // The member span includes its trailing `;`. diff --git a/crates/tsv_ts/src/printer/types/composite.rs b/crates/tsv_ts/src/printer/types/composite.rs index 8d5a45ce0..ca47ad7ea 100644 --- a/crates/tsv_ts/src/printer/types/composite.rs +++ b/crates/tsv_ts/src/printer/types/composite.rs @@ -975,11 +975,8 @@ impl<'a> Printer<'a> { // element, drop comments pulled onto the `[` line (emitted as the // bracket-line prefix below). let skip_delim = if i == 0 { delimiter_pull_pos } else { None }; - inner_parts.extend( - self.build_leading_comments_multiline_opt(prev_end, elem_start, skip_delim), - ); - - inner_parts.push(self.build_type_doc(elem)); + let leading = self.build_leading_comments_multiline(prev_end, elem_start, skip_delim); + inner_parts.push(self.build_list_element_group(leading, self.build_type_doc(elem))); if !is_last { let next_start = t.element_types[i + 1].span().start; diff --git a/crates/tsv_ts/src/printer/types/function_types.rs b/crates/tsv_ts/src/printer/types/function_types.rs index 2605bf2e2..529ca90c1 100644 --- a/crates/tsv_ts/src/printer/types/function_types.rs +++ b/crates/tsv_ts/src/printer/types/function_types.rs @@ -1013,7 +1013,7 @@ impl<'a> Printer<'a> { // Leading comments (after previous comma or `(`); for the first param, // exclude comments already pulled onto the `(` line. let skip_delim = if i == 0 { paren_pull_pos } else { None }; - inner_parts.extend(self.build_leading_comments_multiline_opt( + inner_parts.extend(self.build_leading_comments_multiline( prev_end, param_start, skip_delim, diff --git a/crates/tsv_ts/src/printer/types/helpers.rs b/crates/tsv_ts/src/printer/types/helpers.rs index 14fa74e8b..bab766783 100644 --- a/crates/tsv_ts/src/printer/types/helpers.rs +++ b/crates/tsv_ts/src/printer/types/helpers.rs @@ -110,20 +110,24 @@ pub fn is_hugging_union_type_arg(ty: &TSType<'_>) -> bool { && u.types.iter().any(|t| matches!(t, TSType::TypeLiteral(_) | TSType::Mapped(_)))) } -/// Find the `TSParenthesizedType` that directly wraps a union, walking through any -/// redundant nested parens. Returns `None` when `ts_type` is a bare union (the parens -/// are synthetic, added by the printer for precedence — no source comments to preserve). +/// Find the `TSParenthesizedType` that directly wraps `ts_type`'s underlying type, +/// walking through any redundant nested parens. Returns `None` when `ts_type` is not +/// parenthesized in source (the parens are synthetic, added by the printer for +/// precedence — there is no author gap, so no comments to preserve). /// -/// Used to recover the paren span so `build_parenthesized_union_doc` can emit comments -/// the user wrote inside retained parens (`(/* c */ a | b)`, `(a | b /* c */)`). -pub(super) fn immediate_union_paren<'a>( +/// Used to recover the paren span so the paren-retaining member printers can emit +/// comments the user wrote inside retained parens — `build_parenthesized_union_doc` +/// (`(/* c */ a | b)`, `(a | b /* c */)`) and +/// `build_parenthesized_intersection_trailing_object_doc` (`(// c⏎a & { … })`). Both are +/// handed their already-unwrapped inner type, so the paren's own gap is invisible to them +/// otherwise, and a comment in it would be silently dropped. +pub(super) fn immediate_paren<'a>( ts_type: &'a TSType<'a>, ) -> Option<&'a internal::TSParenthesizedType<'a>> { match ts_type { TSType::Parenthesized(p) => match p.type_annotation { - TSType::Union(_) => Some(p), - inner @ TSType::Parenthesized(_) => immediate_union_paren(inner), - _ => None, + inner @ TSType::Parenthesized(_) => immediate_paren(inner), + _ => Some(p), }, _ => None, } diff --git a/crates/tsv_ts/src/printer/types/mod.rs b/crates/tsv_ts/src/printer/types/mod.rs index d8b6da2fd..7ac1066fa 100644 --- a/crates/tsv_ts/src/printer/types/mod.rs +++ b/crates/tsv_ts/src/printer/types/mod.rs @@ -29,7 +29,7 @@ mod type_params; mod union_intersection; // Re-export public items from helpers -pub use helpers::{should_hug_union_type, unwrap_parenthesized}; +pub use helpers::unwrap_parenthesized; // Re-export for submodules to use `super::X` instead of `super::super::X` pub(super) use super::{CommentFilter, CommentSpacing, Printer}; diff --git a/crates/tsv_ts/src/printer/types/type_annotation.rs b/crates/tsv_ts/src/printer/types/type_annotation.rs index f04103c4f..f92171e07 100644 --- a/crates/tsv_ts/src/printer/types/type_annotation.rs +++ b/crates/tsv_ts/src/printer/types/type_annotation.rs @@ -5,7 +5,7 @@ // - Width-aware wrapping for type arguments // - Return type annotations -use super::helpers::{should_hug_union_type, type_args_should_wrap_for_return_type}; +use super::helpers::type_args_should_wrap_for_return_type; use super::{CommentSpacing, Printer}; use crate::ast::internal::{self, TSType}; use crate::printer::layout::hang_after_operator; @@ -30,8 +30,18 @@ impl<'a> Printer<'a> { let colon_end = annotation.span.start + 1; // After the `:` let type_start = annotation.type_annotation.span().start; + // Zero-comment gate over the `:`→type gap, computed once and reused by every + // arm below (the union arm and the simple fall-through ask for this exact + // range; a type annotation is among the most frequent TS constructs and a + // comment inside one is rare). It also subsumes the line-comment check that + // follows: ownership only ever binds a *block* comment (`owned ⇒ is_block`), + // so a line comment is always in the to-emit set and no gap without to-emit + // comments can hold one. The wrapping sibling + // (`build_type_annotation_doc_with_wrapping`) already hoists this way. + let gap_has_comments = self.has_comments_to_emit_between(colon_end, type_start); + // Check if there's a line comment between : and the type - if self.has_line_comments_between(colon_end, type_start) { + if gap_has_comments && self.has_line_comments_between(colon_end, type_start) { // Uniform forced-continuation indent (`build_continuation_indent`): the // first comment trails `:` on its line, then the remaining comments and the // type drop one indent level so the continuation reads as part of this @@ -66,7 +76,7 @@ impl<'a> Printer<'a> { let type_doc = self.build_union_type_doc(u); // Comments between `:` and the union type (e.g., `: /* c */ A | B`); // omit the empty child on the comment-free common path. Byte-identical. - let hung = if self.has_comments_to_emit_between(colon_end, type_start) { + let hung = if gap_has_comments { let comments_doc = self.build_comments_between( colon_end, type_start, @@ -88,7 +98,7 @@ impl<'a> Printer<'a> { colon_end, type_start, annotation.type_annotation, - self.has_comments_to_emit_between(colon_end, type_start), + gap_has_comments, ), } } @@ -252,8 +262,8 @@ impl<'a> Printer<'a> { // break-after-colon fallback. `union_return_hugs` scopes it: a // `Promise<…> | null` `TSTypeReference` member is excluded (the sanctioned // `return_type_generic_union` print-width family, handled by the - // `should_hug_union_type` branch below), and a member/gap comment - // disqualifies the hug. + // `union_prints_hugged` branch below), and any comment that makes the printer + // decline the hug disqualifies it here too. if self.union_return_hugs(value_type, u, colon_end, value_type_start) { return match comments_doc { Some(c) => d.concat(&[d.text(": "), c, type_doc]), @@ -261,7 +271,7 @@ impl<'a> Printer<'a> { }; } - if should_hug_union_type(u) { + if self.union_prints_hugged(u) { // A should-hug union that didn't take the brace-hug above: a // `TSTypeReference` object-like member with only void siblings // (`Promise<…> | null`), or a brace union whose member/gap comment diff --git a/crates/tsv_ts/src/printer/types/type_literal.rs b/crates/tsv_ts/src/printer/types/type_literal.rs index 05ae56ecc..70b759778 100644 --- a/crates/tsv_ts/src/printer/types/type_literal.rs +++ b/crates/tsv_ts/src/printer/types/type_literal.rs @@ -9,7 +9,7 @@ use super::super::CommentVec; use super::super::comments_to_emit_in_range; use super::Printer; -use super::helpers::{immediate_union_paren, unwrap_parenthesized}; +use super::helpers::{immediate_paren, unwrap_parenthesized}; use crate::ast::internal::{ TSIntersectionType, TSParenthesizedType, TSType, TSTypeElement, TSTypeLiteral, TSUnionType, }; @@ -81,11 +81,7 @@ impl<'a> Printer<'a> { docs.push(d.literalline()); } docs.push(d.hardline()); - docs.extend(self.build_leading_comments_with_blank_lines( - &leading_comments, - member_start, - false, - )); + docs.extend(self.build_leading_comments_before(&leading_comments, member_start)); docs } @@ -195,17 +191,16 @@ impl<'a> Printer<'a> { && let Some(last) = intersection.types.last() && let TSType::TypeLiteral(obj) = unwrap_parenthesized(last) { - return self - .build_parenthesized_intersection_trailing_object_doc(intersection, obj); + return self.build_parenthesized_intersection_trailing_object_doc( + intersection, + obj, + immediate_paren(ts_type), + ); } // Special case: parenthesized union type if let TSType::Union(union) = unwrap_parenthesized(ts_type) { - return self.build_parenthesized_union_doc( - union, - immediate_union_paren(ts_type), - false, - ); + return self.build_parenthesized_union_doc(union, immediate_paren(ts_type), false); } // Default case: parenthesize and indent the inner type. The closing @@ -334,11 +329,46 @@ impl<'a> Printer<'a> { &self, intersection: &TSIntersectionType<'_>, trailing_obj: &TSTypeLiteral<'_>, + paren: Option<&TSParenthesizedType<'_>>, ) -> DocId { let d = self.d(); // Build opening: (A & B & { let mut opening_parts: DocBuf = smallvec![d.text("(")]; + // Comments the author wrote inside retained parens, ahead of the intersection + // (`(/* c */ a & { … })`, `(// c⏎a & { … })`) — kept in place, as the union + // sibling `build_parenthesized_union_doc` keeps them. This function is handed the + // already-unwrapped `intersection`, so the paren's own gap is invisible to every + // other emitter and a comment there would be silently DROPPED. + // + // A *line* comment reaches here only for a FIRST union member: a later member's + // is relocated to trail the previous member by + // `build_union_type_doc_with_line_comments`, which then builds the inner type + // directly and never routes here — so there is no double-print to guard against. + if let Some(p) = paren { + let mut lead: DocBuf = DocBuf::new(); + for comment in + comments_to_emit_in_range(self.comments, p.span.start + 1, intersection.span.start) + { + lead.push(self.build_comment_doc(comment)); + if comment.is_block { + lead.push(d.text(" ")); + } else { + // A `//` runs to end-of-line — without the break it would swallow the + // intersection that follows it on the line. + lead.push(d.hardline()); + } + } + if !lead.is_empty() { + // `indent`, because that break places the intersection's own first line: + // it belongs one level in from the `(`, matching the default-paren path + // (`d.indent(self.build_type_doc(…))` above) that every other paren-retained + // member shape takes. A block comment carries no break, so the indent is + // inert for it. + opening_parts.push(d.indent(d.concat(&lead))); + } + } + // Build intersection types except the last one (the object) let types_before_object = &intersection.types[..intersection.types.len() - 1]; for (i, t) in types_before_object.iter().enumerate() { diff --git a/crates/tsv_ts/src/printer/types/type_params.rs b/crates/tsv_ts/src/printer/types/type_params.rs index 93d989806..dbbc77df9 100644 --- a/crates/tsv_ts/src/printer/types/type_params.rs +++ b/crates/tsv_ts/src/printer/types/type_params.rs @@ -100,7 +100,7 @@ impl<'a> Printer<'a> { // Leading comments (after previous comma or `<`); for the first param, // exclude comments already pulled onto the `<` line. let skip_delim = if i == 0 { angle_pull_pos } else { None }; - inner_parts.extend(self.build_leading_comments_multiline_opt( + inner_parts.extend(self.build_leading_comments_multiline( prev_end, param_start, skip_delim, @@ -684,7 +684,9 @@ impl<'a> Printer<'a> { ); if has_line && !has_trailing { let leading = - self.build_leading_comments_multiline(inst.span.start + 1, param_start); + // `None`: this hug path emits no delimiter-line prefix, so nothing + // was pulled onto the `<` line to exclude here. + self.build_leading_comments_multiline(inst.span.start + 1, param_start, None); if !leading.is_empty() { let param_doc = if type_position { self.build_type_arg_doc(param, is_multi) @@ -719,7 +721,7 @@ impl<'a> Printer<'a> { // drop comments pulled onto the `<` line (emitted as the angle-line // prefix below). let skip_delim = if i == 0 { delimiter_pull_pos } else { None }; - inner_parts.extend(self.build_leading_comments_multiline_opt( + inner_parts.extend(self.build_leading_comments_multiline( prev_end, param_start, skip_delim, diff --git a/crates/tsv_ts/src/printer/types/union_intersection.rs b/crates/tsv_ts/src/printer/types/union_intersection.rs index 36f3e44dc..67bce48eb 100644 --- a/crates/tsv_ts/src/printer/types/union_intersection.rs +++ b/crates/tsv_ts/src/printer/types/union_intersection.rs @@ -223,9 +223,7 @@ impl<'a> Printer<'a> { // nested *inside* a member (e.g. `{ /* c */ a: 1 }`) attaches to a child // node, not the member, so it must not block the hug — the member's own // doc renders it. - if (!has_comments || !self.union_has_comments_between_members(union)) - && should_hug_union_type(union) - { + if self.union_prints_hugged(union) { let mut parts = DocBuf::new(); // Extract leading block comments before the first type // (e.g., `| /* c */ A` — comment between leading `|` and first member) @@ -330,16 +328,26 @@ impl<'a> Printer<'a> { parts.push(d.if_break(d.text("| "), d.empty())); // Extract leading block comments before the first type - // (e.g., `| /* c */ A | B` — comment between leading `|` and first member) + // (e.g., `| /* c */ A | B` — comment between leading `|` and first member). + // + // `indent` for the same reason as the line-comment path's run: when this + // run ends in a break — an own-line multi-line block, or its soft `line` + // breaking as the union expands — it is the run that places the member's + // own first line, which then belongs at the per-member offset rather than + // flush under the `|`. Unconditional because `indent` binds only the + // breaks inside it, so a run that hugs its member is unaffected. if has_comments { - parts.push( + parts.push(d.indent( self.build_member_leading_block_comments(union.span.start, type_start), - ); + )); } } // Apply Prettier's per-member `align(2, …)` offset (rendered as one - // whole tab) — see `build_union_member_offset_doc`. + // whole tab) — see `build_union_member_offset_doc`. The first member's + // leading run takes that offset separately, above: the run is indented, never + // this call's result, so the object-literal and default-paren members that + // supply their own indent keep declining it. parts.push(self.build_union_member_offset_doc(t, member_parens)); // Add trailing block comments after this type (before the next `|` separator) @@ -392,7 +400,12 @@ impl<'a> Printer<'a> { let TSType::Union(union) = ty else { return None; }; - if should_hug_union_type(union) { + // `union_prints_hugged`, not the bare syntactic `should_hug_union_type`: this + // must agree with the layout `build_union_type_doc` will actually take. A comment + // can make it decline the hug and expand, and then the keyword has to break like + // any other non-hugging union — asking the syntactic form alone keeps `as ` glued + // while the members explode below it. + if self.union_prints_hugged(union) { return None; } // The union members form their own group (`build_union_type_doc`), nested @@ -440,6 +453,27 @@ impl<'a> Printer<'a> { let type_start = t.span().start; let type_end = t.span().end; + // The **first** member's leading-comment run, built here rather than at the + // `| ` prefix below so the arm that emits it decides whether it takes the + // per-member offset — the paren-union arm declines it, the general arm takes + // it. Both block and line comments are emitted from here; a line comment + // requires multiline and places the member on the next line (`| // c⏎ A`). + // + // ⚠️ Empty for every later member, and the arm chain below consumes it by + // move — an arm that neither extends nor inspects it is a **dropped comment** + // (`comments:audit` is the corpus-wide guard). The relocated-paren arm can't + // coexist with a non-empty run: its `relocated_paren_leading` is empty unless + // `i > 0`. + // + // `None` for `skip_delim`: the union's leading `|` is not run through + // `delimiter_line_comment_prefix`, unlike the bracket/angle/paren lists, so + // no comment was pulled onto a delimiter line to exclude here. + let first_leading = if i == 0 { + self.build_leading_comments_multiline(union.span.start, type_start, None) + } else { + DocBuf::new() + }; + // For non-first members, detect leading line comments inside the // parens of a TSParenthesizedType wrapper. Prettier relocates these // to trail the previous member (e.g., `a | (// c\n b)` becomes @@ -538,28 +572,11 @@ impl<'a> Printer<'a> { parts.push(d.text("| ")); } } else { - // First type: always has `| ` prefix when multiline + // First type: always has `| ` prefix when multiline. Its leading run was + // built above and is emitted by the arm chain below. parts.push(d.text("| ")); - - // Extract leading comments before the first type. Both block and - // line comments are emitted here — line comments require multiline - // and place the type on the next line (e.g., `| // c\n A`). - parts.extend(self.build_leading_comments_multiline(union.span.start, type_start)); } - // The per-member offset shifts a member's *internal* break lines past - // the `| ` prefix; it must only apply when the member's first line is - // glued to `| `. The first member is dropped onto its own line by a - // leading own-line comment — either before it (`| // c\n a`) or inside - // its stripped parens (`(// c\n a)`) — where the offset would wrongly - // indent the member's own first line. Non-first members keep their - // leading line comments before the pipe, so they stay glued. - let member_on_own_line = i == 0 - && (self - .comments_on_page_between(union.span.start, type_start) - .any(|c| !self.comment_hugs_next(c, type_start)) - || matches!(t, TSType::Parenthesized(p) if self.paren_has_leading_line_comment(p))); - // Add the type with the same per-member offset as the main path // (`build_union_member_offset_doc`). When we relocated leading line // comments from inside a `TSParenthesizedType` wrapper, build the inner @@ -569,6 +586,9 @@ impl<'a> Printer<'a> { if !relocated_paren_leading.is_empty() && let TSType::Parenthesized(p) = t { + // Unreachable with a held run — this arm needs `i > 0`, the run needs + // `i == 0` (see its declaration), so there is nothing here to emit. + debug_assert!(first_leading.is_empty()); let inner = p.type_annotation; if let TSType::Union(union) = inner { // `build_parenthesized_union_doc` lays out `(`/`)` on their own @@ -600,21 +620,38 @@ impl<'a> Printer<'a> { // to `build_parenthesized_union_doc` so it is not dropped. Take the // per-member offset like any other paren-union member (matching the // `is_paren_union_member` arm of `build_union_member_offset_doc`). + parts.extend(first_leading); parts.push(d.indent(self.build_parenthesized_union_doc( inner_union, Some(p), true, ))); - } else if member_on_own_line { - // Dropped onto its own line by a leading comment — emit without the - // offset (it would indent the member's own first line). Objects - // still self-indent via `build_union_member_object_literal_doc`. - if let TSType::TypeLiteral(obj) = t { - parts.push(self.build_union_member_object_literal_doc(obj)); - } else { - parts.push(self.build_type_doc_maybe_parens(t, member_parens)); - } } else { + // The leading run takes the member's per-member offset. Whenever the run + // ends in a break it is the run — not the `| ` prefix — that places the + // member's own first line, so an unindented run would strand that line + // one level shallower than the member's internal breaks. Prettier has the + // same shape: `align(2, print())`, whose `print()` carries the leading + // comments. + // + // The wrapper is applied whenever there IS a run, never keyed on whether + // the run breaks: `indent` binds only the line breaks *inside* it, so a + // run whose comments all hug the member is pure text and the wrapper is + // inert. "Does this run drop the member onto its own line?" is a question + // the doc structure already answers — asking it again with a predicate + // would be a second gate that can drift from this one. + // + // Indent the RUN, never `build_union_member_offset_doc`'s result: that + // function owns the opt-outs (an object literal and a default-paren + // member supply their own indent and decline the offset), so wrapping + // its result would double-indent exactly those two — the member's body + // two columns past prettier, its closing delimiter out of line with its + // opener. Sound because `indent` is a per-line property, so + // `indent(concat([run, member]))` and `concat([indent(run), member])` + // agree wherever the member does take the offset. + if !first_leading.is_empty() { + parts.push(d.indent(d.concat(&first_leading))); + } parts.push(self.build_union_member_offset_doc(t, member_parens)); } @@ -656,12 +693,80 @@ impl<'a> Printer<'a> { gap_start: u32, gap_end: u32, ) -> bool { + // Two questions, each asked of the one predicate that owns it. The **brace** + // narrowing is this site's own (`is_hugging_union_type_arg` — a + // `Promise<…> | null` `TSTypeReference` member is excluded, the sanctioned + // `return_type_generic_union` print-width family), and so is the `:`→union gap. + // But whether the union HUGS AT ALL belongs to [`Self::union_prints_hugged`] and + // is not re-derived here: this gate used to spell out its own subset of that + // predicate's comment checks and missed the leading `|`→first-member line + // comment, so a comment that made the printer decline the hug still read as + // "hug" here and kept `: ` glued while the members exploded below it. is_hugging_union_type_arg(value_type) - && !self.union_has_comments_between_members(union) + && self.union_prints_hugged(union) && !self.has_comments_to_emit_between(gap_start, gap_end) } - pub(crate) fn union_has_comments_between_members(&self, union: &TSUnionType<'_>) -> bool { + /// Whether [`Self::build_union_type_doc`] will actually take its **hug** path — + /// the inline `{ … } | null` form where the object member owns its own expansion. + /// + /// The single source of truth for that question, because two places must agree on + /// it: the union printer (which lays the members out) and the type-alias RHS + /// (`build_type_alias_doc`, which decides whether to break after `=`). Asking the + /// bare syntactic [`should_hug_union_type`] at the alias while the printer declines + /// the hug for a comment splits them — the alias keeps `= ` while the union expands, + /// yielding `type A = | // c⏎{ a: 1 }⏎| null` where a non-hugging union of the same + /// shape correctly breaks after the `=`. + /// + /// Beyond the syntactic shape, a comment prettier's `shouldHugUnionType` would bail + /// on disqualifies the hug: + /// + /// - **between two members** — prettier's `types.some((t) => hasComment(t))`, which + /// in the detached model lives in the inter-member gap; + /// - a **line** comment in the leading `|`→first-member gap — the hug emits that gap + /// block-only, so a line comment there would be silently DROPPED, and it could not + /// be inlined regardless (a `//` runs to end-of-line and would swallow the member). + /// `union_has_comments_between_members` cannot answer this: the gap is *before* the + /// first member, not *between* two. A **block** there stays hugged and inline + /// (`/* c */ { a: 1 } | null`), matching prettier. + /// + /// A comment nested *inside* a member (`{ /* c */ a: 1 }`) attaches to a child node, + /// not the member, so it never blocks the hug — the member's own doc renders it. + /// + /// **Axis.** This is a layout gate, so it asks the **on-page** question — an owned + /// comment occupies the page and must block the hug like any other. The delegates it + /// guards read the **to-emit** axis, which is sound here only because ownership is + /// set exclusively in expression position (`parser/expression.rs`): no comment in a + /// *type*'s gaps is ever owned, so within a union the two axes coincide. Should + /// ownership ever reach type position, `union_has_comments_between_members` becomes + /// the weak link — the on-page fast path would fall through and the emit-keyed + /// pairwise scan would report "no comments" for an owned one, hugging a union whose + /// members the printer expands. + pub(crate) fn union_prints_hugged(&self, union: &TSUnionType<'_>) -> bool { + if !should_hug_union_type(union) { + return false; + } + // Zero-comment fast path — an **on-page** question, since it short-circuits the + // comment gates below. + if !self.has_comments_on_page_between(union.span.start, union.span.end) { + return true; + } + !self.union_has_comments_between_members(union) + && !union.types.first().is_some_and(|first| { + self.has_line_comments_between(union.span.start, first.span().start) + }) + } + + /// Whether any comment sits in a gap *between* two consecutive members — the + /// detached-model spelling of prettier's `types.some((t) => hasComment(t))` + /// (`shouldHugType`'s bail). + /// + /// Private, and deliberately so: it answers one clause of "does this union hug", + /// never that question itself. [`Self::union_prints_hugged`] owns the whole answer, + /// and is the only caller — a layout gate that reaches past it to this clause is + /// re-deriving the layout with a subset of the rule, which is exactly how the + /// leading-`|` line comment was missed. + fn union_has_comments_between_members(&self, union: &TSUnionType<'_>) -> bool { // Zero-comment window gate: one binary search over the whole union span before // the N-1 pairwise between-member searches. Each pairwise range lies within // `[union.span.start, union.span.end]`, so with no comment inside the union diff --git a/docs/conformance_prettier.md b/docs/conformance_prettier.md index 9c9419e66..f315e8f7b 100644 --- a/docs/conformance_prettier.md +++ b/docs/conformance_prettier.md @@ -279,7 +279,7 @@ The boolean **connectors** `and`/`or`/`not` are **preserved** (`@supports (a: b) ### CSS: Layout -**Greedy fill overflow** (◆print_width) — [comma_separated_greedy_fill](../tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/): Prettier's `fill()` algorithm allows lines to exceed `printWidth` by 1 char when fill segments exactly consume remaining width and the parent adds trailing punctuation. tsv treats `printWidth` as a hard limit. +**Greedy fill overflow** (◆print_width) — [comma_separated_greedy_fill](../tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/): Prettier's `fill()` algorithm allows lines to exceed `printWidth` by 1 char when fill segments exactly consume remaining width and the parent adds trailing punctuation. tsv treats `printWidth` as a hard limit. > **Related fill boundary divergences**: Several fixtures test variations of Prettier allowing lines to exceed `printWidth`. These share a common root cause—Prettier's `fill()` algorithm boundary conditions: > @@ -606,6 +606,10 @@ the cast keywords diverge from tsc, in tsv's favor of the drop-in oracle. These fixtures exercise the [Tabs-Only Indentation Philosophy](#tabs-only-indentation-philosophy): Prettier's `align(2, …)` for broken union members emits `tabs + 2 spaces` under `--use-tabs`, while tsv rounds the 2-column offset up to a whole tab everywhere. +Every entry here is a **representation** difference at the same visual width (`tabWidth = 2`), never a different layout — and there are no known exceptions; an entry whose two forms differ in *width* is a bug, not a member of this family. That is the line to hold when touching it, and it cuts both ways: *dropping* the offset — so the member sits two columns shallower than prettier — is not "tabs-only" but a second, unsanctioned divergence wearing the philosophy's name; *doubling* it is the same mistake mirrored. Both leading-comment entries below dropped it until `bug123`; the tell was their own READMEs asserting "the visual result is equivalent" while describing a member kept flush under the `|`, which cannot both be true. + +When a member is dropped onto its own line by a leading comment, the offset covers the **comment run and the member together** (prettier's `align(2, print())`, whose `print()` carries the leading comments) — offsetting only the member would leave its first line, which the run's `hardline` places, one level shallower than the member's own internal breaks. In tsv that is spelled by indenting the **run**, never the member doc: `build_union_member_offset_doc` owns the opt-outs — an object literal and a default-paren member each supply their own indent and decline the offset — so wrapping *its result* would double-indent exactly those two, pushing their body two columns past prettier and leaving their closing delimiter out of line with its opener. The two shapes are pinned as cases D and E of [union_intersection_parens_leading_line_comment](../tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/); a member with no internal breaks shows no offset at all, so the cases that match prettier byte-for-byte live in that fixture's [non-divergence sibling](../tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/). + - Union object member — [union_object_member](../tests/fixtures/typescript/types/union_object_member_prettier_divergence/) - Union hugged object — [union_hug_object](../tests/fixtures/typescript/types/union_hug_object_prettier_divergence/) - Union parenthesized object — [union_parens_object](../tests/fixtures/typescript/types/union_parens_object_prettier_divergence/) @@ -615,8 +619,10 @@ These fixtures exercise the [Tabs-Only Indentation Philosophy](#tabs-only-indent - Union member break + line comment — [union_member_long_line_comment](../tests/fixtures/typescript/types/comments/union_member_long_line_comment_prettier_divergence/) - Union paren-union member — [union_paren_union_member_long](../tests/fixtures/typescript/types/union_paren_union_member_long_prettier_divergence/) - Union paren member + line comment — [union_paren_member_long_line_comment](../tests/fixtures/typescript/types/comments/union_paren_member_long_line_comment_prettier_divergence/) -- Union member leading multi-line block comment — [union_member_leading_block_comment](../tests/fixtures/typescript/types/comments/union_member_leading_block_comment_prettier_divergence/) -- Union member leading line comment (forced onto its own line) — [union_intersection_parens_leading_line_comment](../tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/) +- Union member leading multi-line block comment — the block-comment sibling of the entry below; the run takes the offset the same way, which also aligns the comment's continuation `*` under its opening `/*` — [union_member_leading_block_comment](../tests/fixtures/typescript/types/comments/union_member_leading_block_comment_prettier_divergence/) +- Union member leading line comment (dropped onto its own line; the offset covers the run + the member, including the object-literal and default-paren members that supply their own indent) — [union_intersection_parens_leading_line_comment](../tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/) +- Union **hug** declined by a leading line comment — a `//` in the leading `|`→first-member gap of a `{ … } | null` union expands it (both formatters; the hug would otherwise drop the comment, since it emits that gap block-only and a `//` can't be inlined). Only the member alignment differs, exactly as in the entry above — [union_hug_leading_line_comment](../tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/) +- Union first-member leading block-comment run — the run itself matches prettier (a glued pair stays glued, own-line blocks keep their lines); only the alignment differs — [union_first_member_glued_block_comment](../tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/) ### TypeScript: Template Literals @@ -679,6 +685,7 @@ Prettier moves comments between syntactic boundaries into adjacent blocks, paren - Member-only chain interior line comment, trailing non-null `!` (no calls) → Same relocation as above; both formatters keep the `!` glued to its member (`.bar!` / `?.bar!`) — a break before a non-null `!` is a syntax error (`[no LineTerminator here]`), so it never lands on its own line. The non-null variant of [member_only_interior_line_comment](#comment-relocation) — [member_only_non_null_line_comment](../tests/fixtures/typescript/expressions/calls/chained/member_only_non_null_line_comment_prettier_divergence/) - Array element end-of-line block comment → Across the element's comma, from leading the next element to trailing the previous one (`['aaaa', /* c */⏎'bbbb']` → `['aaaa' /* c */, 'bbbb']`, flipping the binding from `'bbbb'` to `'aaaa'`); prettier classifies on newlines alone (`endOfLine`), so the comma — which carries the association — plays no part. tsv keeps the comment after the comma. **Not** the sanctioned pure-separator trail: that covers a same-line *line* comment (`A // c⏎, B` → `A, // c`), where the binding never changes and a `//` running to end-of-line leaves no other rendering; a block comment flips its binding and renders fine either side, so the move is unforced — [end_of_line_block_comment](../tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/) - Block comment in computed `[]` → Before member chain (hoisted) — [block_comment_computed_member_long](../tests/fixtures/typescript/syntax/comments/block_comment_computed_member_long_prettier_divergence/) +- Computed member-access `[]` leading comment run (bracket-break path, incl. `?.[`) → Prettier empties the brackets: the whole run is hoisted out to before the object and the `[`-line comment is stranded between the object and its index (`/* c1 */ /* c2 */⏎obj // force⏎[idx]`), so each comment changes what it reads as being about; tsv keeps all of them inside the brackets the author wrote them in — [computed_index_glued_block_comment](../tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/) - Switch case colon comment → Before colon or into body — [case_colon_comment](../tests/fixtures/typescript/statements/switch/case_colon_comment_prettier_divergence/) - Switch case/`default` colon, comment contains a colon (scan robustness) → `case` preserved (plain); `default` into the body — [case_colon_in_comment](../tests/fixtures/typescript/statements/switch/case_colon_in_comment_prettier_divergence/) - Class property definite `!` → Before `!` modifier — [property_definite_comment](../tests/fixtures/typescript/statements/class/property_definite_comment_prettier_divergence/) @@ -791,7 +798,7 @@ Prettier moves comments between syntactic boundaries into adjacent blocks, paren - Union infix `\|` line comment → Trailing on previous member — [union_infix_pipe_line_comment](../tests/fixtures/typescript/types/comments/union_infix_pipe_line_comment_prettier_divergence/) - Retained paren union member comment → A trailing block comment hoisted after `)`; a leading one stays inside — [union_intersection_retained_paren_comment](../tests/fixtures/typescript/types/union_intersection_retained_paren_comment_prettier_divergence/) - Retained paren union member line cmt → Comment stays inside parens (both); tsv keeps inner union inline (union-fit), prettier explodes it one-per-line — [union_intersection_retained_paren_line_comment](../tests/fixtures/typescript/types/union_intersection_retained_paren_line_comment_prettier_divergence/) -- Retained paren union leading line cmt → Before the 1st member (out of parens) — [union_intersection_retained_paren_leading_line_comment](../tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/) +- Retained paren union leading line cmt → Before the 1st member (out of parens); tsv keeps it inside the parens. Covers a paren-union member and a paren-intersection-with-trailing-object member, whose aligned layout is built from the already-unwrapped inner type — so the paren's own gap must be threaded in, or the comment is silently dropped — [union_intersection_retained_paren_leading_line_comment](../tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/) - Retained paren member **own-line leading** line cmt (collapsing intersection) → Out of parens, onto its own line before `(`, intersection broken; tsv keeps it inside the parens, forcing the member to break open — [union_intersection_paren_member_own_line_comment](../tests/fixtures/typescript/types/union_intersection_paren_member_own_line_comment_prettier_divergence/) - Retained paren intersection member cmt → Outside the parens (after `)`/`(`) — [retained_paren_intersection_member_comment](../tests/fixtures/typescript/types/retained_paren_intersection_member_comment_prettier_divergence/) - Type alias head to `=` (line) → After `=` (right of operator) — [type_alias_line_pre_equals](../tests/fixtures/typescript/types/comments/type_alias_line_pre_equals_prettier_divergence/) @@ -911,7 +918,7 @@ The deliberate exclusions are constructs where the following token isn't part of **Call open paren `(` trailing**: `fn( // c` / `fn( /* c */` (a comment on the same line as a call's opening `(`) → Prettier relocates it to its own line as the first argument's leading comment (`fn(\n\t// c\n\t…)`). tsv keeps it trailing the `(` (`fn( // c\n\t…)`), treating the author's placement after `(` as a trailing comment on that line. This applies only when the call expands (a line comment after `(`, or own-line content among the args); a block comment that hugs the arg in a call that stays inline (`fn(/* c */ a)`) is unchanged and matches Prettier. When the author instead writes the comment on its own line, both formatters keep it there — the two positions are dual-stable. Applies to simple-callee calls (`call_formatting.rs`), member-chain calls (`chain_args.rs`), and `new` expressions (`new_expression.rs`). For chains, a block comment trailing `(` plus an own-line leading comment keep source order (the naive handling reverses them). For `new`, a line comment trailing `(` (`new Foo( // c\n\ta)`) is preserved rather than dropped entirely (content loss); prettier relocates it (line or block) to its own line inside the parens as the first argument's leading comment (`new Foo(\n\t// c\n\ta)`), the same as the simple-callee and member-chain forms. -**Object/array/block open-delimiter trailing**: the same position-preservation rule as the call `(` case, generalized to the other opening delimiters. A comment on the same line as an object literal's `{` (`const o = { // c`), an array literal's `[` (`const a = [ // c`), a block body's `{` (`function f() { // c`, plain `{ // c`, arrow `=> { // c`), a type-parameter list's `<` (`function f< // c`, also classes/interfaces/type aliases/arrows), a function/constructor-type parameter list's `(` (`type Fn = ( // c`, `new ( // c`), a **value-level function-definition** parameter list's `(` (`function fn( // c`, `function ( // c`, `( // c ) => …`, and class method / constructor / setter — [open_paren_line_comment](../tests/fixtures/typescript/declarations/function/open_paren_line_comment_prettier_divergence/), [method_open_paren_line_comment](../tests/fixtures/typescript/statements/class/method_open_paren_line_comment_prettier_divergence/)), an object/array destructuring pattern's `{`/`[` (`const { // c } = o`, `const [ // c ] = a`), a `namespace`/`module` body's `{` (`namespace N { // c`, `module M { // c`), a class/interface/enum body's `{` (`class C { // c`, `interface I { // c`, `enum E { // c`), a type literal's `{` (`type T = { // c`), an import/export specifier list's `{` (`import { // c`, `export { // c`), a tuple type's `[` (`type T = [ // c`), an index signature's `[` (`[ // c\n\tk: V]`), a computed property/member key's `[` (`{ [ // c\n\tfoo]: 1 }`, also class members, destructuring, and interface/type-literal members), a mapped-type key's `[` (`{ [ // c\n\tK in keyof T]: V }` — prettier drops it to its own line), a computed member-access index's `[` (element access, `arr[ // c\n\ti]`, including optional `?.[` — prettier relocates it to trail the object), or a multi-argument type-argument list's `<` (`Map< // c`) is kept on the delimiter line; Prettier relocates it to its own line as the leading comment of the first element/property/statement/parameter/member/specifier/argument (for a computed key prettier instead relocates it out to the **member's** own leading line, or — class members — leaves it glued flush to the key). This applies only to a **line** comment (or a block comment that co-occurs with one) when the construct expands; an inline block comment that hugs content (`{ /* c */ a: 1 }`, `[/* c */ x]`, ``, `(/* c */ p)`, empty body `{ /* c */ }`) and an own-line block comment (which both formatters keep on its own line) are unchanged and match Prettier. When the author instead writes the comment on its own line, both formatters keep it there — dual-stable. Object literals are handled in `objects.rs`, arrays in `arrays.rs`, block bodies in the shared block-printing path (`expressions/blocks.rs`), type-parameter declarations in `types/type_params.rs` (covering function/class/interface/type-alias/arrow), function/constructor types in `types/function_types.rs`, value-level function-definition parameter lists (function declarations/expressions, arrows, class methods, constructors, setters, and Svelte `{#snippet}` params) in `build_params_doc_with_comments` (`expressions/functions.rs`, via the same `delimiter_line_comment_prefix` helper as the signature path), object/array destructuring patterns in `expressions/patterns.rs`, `namespace`/`module` bodies in the shared statement-list walk (`statements/type_declarations.rs`, reusing `build_statement_list_docs_into`), class/interface/enum bodies in their member loops (`build_class_body_doc` in `statements/class.rs`; `build_type_elements_doc` and `build_enum_declaration_doc` in `statements/type_declarations.rs`), type literals in the multiline member path (`build_type_literal_doc_inner` → `build_multiline_member_prefix_doc`, `types/type_literal.rs`), import/export specifier lists in the shared multiline comma-list builder (`build_hardline_comma_list`, `statements/modules/specifier_list.rs`; the `with {…}` import-attribute brace passes its first attribute's start through the same builder — [with_open_brace_line_comment](../tests/fixtures/typescript/modules/imports/with_open_brace_line_comment_prettier_divergence/)), tuple types in their multiline element path (`build_tuple_type_doc_with_line_comments`, `types/composite.rs`, using `build_leading_comments_multiline_opt` for the first element), index signatures in `build_index_signature_member_doc` (`types/type_members.rs`), computed property/member keys in `build_computed_key_bracket_doc` (`expressions/objects.rs`, its breaking path — a computed key never breaks on width, so a line comment in either in-bracket gap, `[`→key (this case) or key→`]` (the [close-bracket sibling](#comment-relocation)), is the only trigger; block comments and the no-comment case keep the flat layout), mapped-type keys in `build_mapped_type_doc` (`types/composite.rs`, its bracket break path — same line-comment-only trigger, a same-line block stays inline), computed member-access (element access) in `build_computed_member_line_comment_bracket` (`chain/adapter.rs`, incl. `?.[`), and multi-argument type-argument lists in their multiline path (`build_type_arguments_doc_with_line_comments`, `types/type_arguments.rs` for _type_ position; `build_type_parameter_instantiation_doc_with_line_comments`, `types/type_params.rs` for call/`new` _expression_ position — a single-argument leading *line* comment hugs `<`/`>` (a divergence; prettier expands), while a single-argument own-line *block* comment expands to match prettier) — all via the shared `Printer::delimiter_line_comment_prefix` helper (`comments/lists.rs`, wrapping `PartitionedComments` + `should_force_expansion_for_comments`). For the type-param `<` and function/constructor-type `(`, preserving the comment also prevents content loss — otherwise the `<` line comment is dropped and the `(` line comment swallows the following tokens. **Within-scope exceptions** (covered constructs are enumerated above): for type literals, the standard path (type aliases, annotations, function-param literals, intersection-trailing objects) is covered, but the union-member / parenthesized-intersection _alignment_ rendering (`type T = | { // c } | B`) still relocates; type-argument lists are covered in both _type_ position (`Map`) and call/`new` _expression_ position (`foo(x)`, `new Foo(x)`), single-argument lists hug a leading *line* comment (a divergence — prettier expands) but expand an own-line *block* comment to match prettier. The value-level function-definition parameter `(` and the `with {…}` import-attribute brace are covered; the sole remaining relocation in this family is the union-member / parenthesized-intersection _alignment_ rendering above, whose fix is coupled to §Intersection Printer Convergence. +**Object/array/block open-delimiter trailing**: the same position-preservation rule as the call `(` case, generalized to the other opening delimiters. A comment on the same line as an object literal's `{` (`const o = { // c`), an array literal's `[` (`const a = [ // c`), a block body's `{` (`function f() { // c`, plain `{ // c`, arrow `=> { // c`), a type-parameter list's `<` (`function f< // c`, also classes/interfaces/type aliases/arrows), a function/constructor-type parameter list's `(` (`type Fn = ( // c`, `new ( // c`), a **value-level function-definition** parameter list's `(` (`function fn( // c`, `function ( // c`, `( // c ) => …`, and class method / constructor / setter — [open_paren_line_comment](../tests/fixtures/typescript/declarations/function/open_paren_line_comment_prettier_divergence/), [method_open_paren_line_comment](../tests/fixtures/typescript/statements/class/method_open_paren_line_comment_prettier_divergence/)), an object/array destructuring pattern's `{`/`[` (`const { // c } = o`, `const [ // c ] = a`), a `namespace`/`module` body's `{` (`namespace N { // c`, `module M { // c`), a class/interface/enum body's `{` (`class C { // c`, `interface I { // c`, `enum E { // c`), a type literal's `{` (`type T = { // c`), an import/export specifier list's `{` (`import { // c`, `export { // c`), a tuple type's `[` (`type T = [ // c`), an index signature's `[` (`[ // c\n\tk: V]`), a computed property/member key's `[` (`{ [ // c\n\tfoo]: 1 }`, also class members, destructuring, and interface/type-literal members — [computed_key_glued_block_comment](../tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/), which also pins prettier hoisting an in-bracket block comment out to the member's line), a mapped-type key's `[` (`{ [ // c\n\tK in keyof T]: V }` — prettier drops it to its own line — [mapped_key_glued_block_comment](../tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/)), a computed member-access index's `[` (element access, `arr[ // c\n\ti]`, including optional `?.[` — prettier relocates it to trail the object), an angle-bracket type assertion's `<` (`const x = < // c\n\tT>y` — [angle_glued_block_comment](../tests/fixtures/typescript/expressions/type_assertion/angle_glued_block_comment_prettier_divergence/)), or a multi-argument type-argument list's `<` (`Map< // c`) is kept on the delimiter line; Prettier relocates it to its own line as the leading comment of the first element/property/statement/parameter/member/specifier/argument (for a computed key prettier instead relocates it out to the **member's** own leading line, or — class members — leaves it glued flush to the key). This applies only to a **line** comment (or a block comment that co-occurs with one) when the construct expands; an inline block comment that hugs content (`{ /* c */ a: 1 }`, `[/* c */ x]`, ``, `(/* c */ p)`, empty body `{ /* c */ }`) and an own-line block comment (which both formatters keep on its own line) are unchanged and match Prettier. When the author instead writes the comment on its own line, both formatters keep it there — dual-stable. Object literals are handled in `objects.rs`, arrays in `arrays.rs`, block bodies in the shared block-printing path (`expressions/blocks.rs`), type-parameter declarations in `types/type_params.rs` (covering function/class/interface/type-alias/arrow), function/constructor types in `types/function_types.rs`, value-level function-definition parameter lists (function declarations/expressions, arrows, class methods, constructors, setters, and Svelte `{#snippet}` params) in `build_params_doc_with_comments` (`expressions/functions.rs`, via the same `delimiter_line_comment_prefix` helper as the signature path), object/array destructuring patterns in `expressions/patterns.rs`, `namespace`/`module` bodies in the shared statement-list walk (`statements/type_declarations.rs`, reusing `build_statement_list_docs_into`), class/interface/enum bodies in their member loops (`build_class_body_doc` in `statements/class.rs`; `build_type_elements_doc` and `build_enum_declaration_doc` in `statements/type_declarations.rs`), type literals in the multiline member path (`build_type_literal_doc_inner` → `build_multiline_member_prefix_doc`, `types/type_literal.rs`), import/export specifier lists in the shared multiline comma-list builder (`build_hardline_comma_list`, `statements/modules/specifier_list.rs`; the `with {…}` import-attribute brace passes its first attribute's start through the same builder — [with_open_brace_line_comment](../tests/fixtures/typescript/modules/imports/with_open_brace_line_comment_prettier_divergence/)), tuple types in their multiline element path (`build_tuple_type_doc_with_line_comments`, `types/composite.rs`, using `build_leading_comments_multiline` for the first element), index signatures in `build_index_signature_member_doc` (`types/type_members.rs`), computed property/member keys in `build_computed_key_bracket_doc` (`expressions/objects.rs`, its breaking path — a computed key never breaks on width, so a line comment in either in-bracket gap, `[`→key (this case) or key→`]` (the [close-bracket sibling](#comment-relocation)), is the only trigger; block comments and the no-comment case keep the flat layout), mapped-type keys in `build_mapped_type_doc` (`types/composite.rs`, its bracket break path — same line-comment-only trigger, a same-line block stays inline), computed member-access (element access) in `build_computed_member_line_comment_bracket` (`chain/adapter.rs`, incl. `?.[`), angle-bracket type assertions in `build_assertion_broken_cast` (`expressions/mod.rs`, whose broken form is an already-broken group so a leading run's soft `line` is measured against the cast rather than the enclosing assignment), and multi-argument type-argument lists in their multiline path (`build_type_arguments_doc_with_line_comments`, `types/type_arguments.rs` for _type_ position; `build_type_parameter_instantiation_doc_with_line_comments`, `types/type_params.rs` for call/`new` _expression_ position — a single-argument leading *line* comment hugs `<`/`>` (a divergence; prettier expands), while a single-argument own-line *block* comment expands to match prettier) — all via the shared `Printer::delimiter_line_comment_prefix` helper (`comments/lists.rs`, wrapping `PartitionedComments` + `should_force_expansion_for_comments`). For the type-param `<` and function/constructor-type `(`, preserving the comment also prevents content loss — otherwise the `<` line comment is dropped and the `(` line comment swallows the following tokens. **Within-scope exceptions** (covered constructs are enumerated above): for type literals, the standard path (type aliases, annotations, function-param literals, intersection-trailing objects) is covered, but the union-member / parenthesized-intersection _alignment_ rendering (`type T = | { // c } | B`) still relocates; type-argument lists are covered in both _type_ position (`Map`) and call/`new` _expression_ position (`foo(x)`, `new Foo(x)`), single-argument lists hug a leading *line* comment (a divergence — prettier expands) but expand an own-line *block* comment to match prettier. The value-level function-definition parameter `(` and the `with {…}` import-attribute brace are covered; the sole remaining relocation in this family is the union-member / parenthesized-intersection _alignment_ rendering above, whose fix is coupled to §Intersection Printer Convergence. **Declaration keyword comments**: `abstract/* b */class B` → Prettier collects all comments between modifier keywords and emits them before the declaration name: `abstract class /* b */ B`. Similarly, `async /* c */ function* F()` → `async function* /* c */ F()`. tsv preserves comments between their original keywords. **Anonymous function keyword comments**: `function /* c */ ()` → Prettier relocates comments between the keyword and `(` in anonymous function expressions, generators, and export default functions. No params: after `)` before `{`. With params: inside parens before first param. tsv preserves the comment between keyword and parens. Prettier's relocated forms are dual-stable (stable in both formatters); our keyword-adjacent form is only stable in our formatter. diff --git a/tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/README.md b/tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/README.md deleted file mode 100644 index 240aee38e..000000000 --- a/tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# comma_separated_greedy_fill_prettier_divergence - -Prettier's `fill()` allows comma-separated CSS values to exceed printWidth by 1 char when trailing punctuation (`;`) is added after greedy packing. - -tsv: wraps before exceeding 100 chars -Prettier: allows 101 chars (greedy fill + trailing `;`) - -The root cause is Prettier's `fill()` packing to exactly the remaining width (`>= 0` check), then the parent adding `;` which pushes past the limit. - -## Reason - -See [conformance_prettier.md §CSS: Layout](../../../../docs/conformance_prettier.md#css-layout) (`Greedy fill overflow`, Print width). tsv treats printWidth as a hard limit. This affects all comma-separated CSS values (`animation-name`, `font-family`, `background-image`, etc.). - -## Related - -- [comma_space_separated_long](../values/lists/comma_space_separated_long_prettier_divergence/) · [space_separated_long_wrap](../values/lists/space_separated_long_wrap_prettier_divergence/) — sibling fill-boundary print-width divergences diff --git a/tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/README.md b/tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/README.md new file mode 100644 index 000000000..2a7ee3142 --- /dev/null +++ b/tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/README.md @@ -0,0 +1,16 @@ +# comma_separated_greedy_fill_prettier_divergence + +Prettier's `fill()` allows comma-separated CSS values to exceed printWidth by 1 char when trailing punctuation (`;`) is added after greedy packing. + +tsv: wraps before exceeding 100 chars +Prettier: allows 101 chars (greedy fill + trailing `;`) + +The root cause is Prettier's `fill()` packing to exactly the remaining width (`>= 0` check), then the parent adding `;` which pushes past the limit. + +## Reason + +See [conformance_prettier.md §CSS: Layout](../../../../../../docs/conformance_prettier.md#css-layout) (`Greedy fill overflow`, Print width). tsv treats printWidth as a hard limit. This affects all comma-separated CSS values (`animation-name`, `font-family`, `background-image`, etc.). + +## Related + +- [comma_space_separated_long](../comma_space_separated_long_prettier_divergence/) · [space_separated_long_wrap](../space_separated_long_wrap_prettier_divergence/) — sibling fill-boundary print-width divergences diff --git a/tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/expected.json b/tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/expected.json similarity index 100% rename from tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/expected.json rename to tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/expected.json diff --git a/tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/input.svelte b/tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/input.svelte similarity index 100% rename from tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/input.svelte rename to tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/input.svelte diff --git a/tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/output_prettier.svelte b/tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/output_prettier.svelte similarity index 100% rename from tests/fixtures/css/comma_separated_greedy_fill_prettier_divergence/output_prettier.svelte rename to tests/fixtures/css/values/lists/comma_separated_greedy_fill_prettier_divergence/output_prettier.svelte diff --git a/tests/fixtures/css/values/lists/comma_space_separated_long_prettier_divergence/README.md b/tests/fixtures/css/values/lists/comma_space_separated_long_prettier_divergence/README.md index f54a63c63..e72f05bb5 100644 --- a/tests/fixtures/css/values/lists/comma_space_separated_long_prettier_divergence/README.md +++ b/tests/fixtures/css/values/lists/comma_space_separated_long_prettier_divergence/README.md @@ -11,5 +11,5 @@ Print width. tsv treats printWidth as a hard limit. At 100 and 102 chars both fo ## Related -- [comma_separated_greedy_fill](../../../comma_separated_greedy_fill_prettier_divergence/) — same fill boundary pattern +- [comma_separated_greedy_fill](../comma_separated_greedy_fill_prettier_divergence/) — same fill boundary pattern - [space_separated_long_wrap](../space_separated_long_wrap_prettier_divergence/) — single value variant diff --git a/tests/fixtures/css/values/lists/space_separated_long_wrap_prettier_divergence/README.md b/tests/fixtures/css/values/lists/space_separated_long_wrap_prettier_divergence/README.md index a2dbba2d8..d4b27eb21 100644 --- a/tests/fixtures/css/values/lists/space_separated_long_wrap_prettier_divergence/README.md +++ b/tests/fixtures/css/values/lists/space_separated_long_wrap_prettier_divergence/README.md @@ -12,7 +12,7 @@ punctuation; it never exceeds by more — a value content of 101 wraps for both) Print width. tsv treats printWidth as a hard limit, so it breaks one item early rather than let the trailing terminator push the line to 101; Prettier leaves it on one line. Same precise 1-char -trailing-punctuation overage documented at [comma_separated_greedy_fill](../../../comma_separated_greedy_fill_prettier_divergence/). +trailing-punctuation overage documented at [comma_separated_greedy_fill](../comma_separated_greedy_fill_prettier_divergence/). See [conformance_prettier.md §CSS: Values](../../../../../../docs/conformance_prettier.md#css-values) ("Space-separated value wrap"). ## Related diff --git a/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/expected.json b/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/expected.json index 747ed38e2..93cb34a00 100644 --- a/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/expected.json +++ b/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/expected.json @@ -2,7 +2,7 @@ "css": null, "js": [], "start": 0, - "end": 424, + "end": 1261, "type": "Root", "fragment": { "type": "Fragment", @@ -522,6 +522,1071 @@ "type": "Fragment", "nodes": [] } + }, + { + "type": "Text", + "start": 423, + "end": 425, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "Comment", + "start": 425, + "end": 508, + "data": " block comment containing `{` — the unclosed brace must not deepen the scan " + }, + { + "type": "Text", + "start": 508, + "end": 509, + "raw": "\n", + "data": "\n" + }, + { + "type": "RegularElement", + "start": 509, + "end": 545, + "name": "div", + "name_loc": { + "start": { + "line": 14, + "column": 1, + "character": 510 + }, + "end": { + "line": 14, + "column": 4, + "character": 513 + } + }, + "attributes": [ + { + "type": "Attribute", + "start": 514, + "end": 538, + "name": "title", + "name_loc": { + "start": { + "line": 14, + "column": 5, + "character": 514 + }, + "end": { + "line": 14, + "column": 10, + "character": 519 + } + }, + "value": [ + { + "start": 521, + "end": 526, + "type": "Text", + "raw": "text1", + "data": "text1" + }, + { + "type": "ExpressionTag", + "start": 526, + "end": 537, + "expression": { + "type": "Identifier", + "start": 535, + "end": 536, + "loc": { + "start": { + "line": 14, + "column": 26 + }, + "end": { + "line": 14, + "column": 27 + } + }, + "name": "b", + "leadingComments": [ + { + "type": "Block", + "value": " { ", + "start": 527, + "end": 534 + } + ] + } + } + ] + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } + }, + { + "type": "Text", + "start": 545, + "end": 547, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "Comment", + "start": 547, + "end": 687, + "data": " block comment containing a quote or backtick — none of them opens a JS string,\n\tso the attribute's own closing quote is still found " + }, + { + "type": "Text", + "start": 687, + "end": 688, + "raw": "\n", + "data": "\n" + }, + { + "type": "RegularElement", + "start": 688, + "end": 724, + "name": "div", + "name_loc": { + "start": { + "line": 18, + "column": 1, + "character": 689 + }, + "end": { + "line": 18, + "column": 4, + "character": 692 + } + }, + "attributes": [ + { + "type": "Attribute", + "start": 693, + "end": 717, + "name": "title", + "name_loc": { + "start": { + "line": 18, + "column": 5, + "character": 693 + }, + "end": { + "line": 18, + "column": 10, + "character": 698 + } + }, + "value": [ + { + "start": 700, + "end": 705, + "type": "Text", + "raw": "text1", + "data": "text1" + }, + { + "type": "ExpressionTag", + "start": 705, + "end": 716, + "expression": { + "type": "Identifier", + "start": 714, + "end": 715, + "loc": { + "start": { + "line": 18, + "column": 26 + }, + "end": { + "line": 18, + "column": 27 + } + }, + "name": "b", + "leadingComments": [ + { + "type": "Block", + "value": " ' ", + "start": 706, + "end": 713 + } + ] + } + } + ] + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } + }, + { + "type": "Text", + "start": 724, + "end": 725, + "raw": "\n", + "data": "\n" + }, + { + "type": "RegularElement", + "start": 725, + "end": 766, + "name": "div", + "name_loc": { + "start": { + "line": 19, + "column": 1, + "character": 726 + }, + "end": { + "line": 19, + "column": 4, + "character": 729 + } + }, + "attributes": [ + { + "type": "Attribute", + "start": 730, + "end": 759, + "name": "title", + "name_loc": { + "start": { + "line": 19, + "column": 5, + "character": 730 + }, + "end": { + "line": 19, + "column": 10, + "character": 735 + } + }, + "value": [ + { + "start": 737, + "end": 742, + "type": "Text", + "raw": "text1", + "data": "text1" + }, + { + "type": "ExpressionTag", + "start": 742, + "end": 758, + "expression": { + "type": "Identifier", + "start": 756, + "end": 757, + "loc": { + "start": { + "line": 19, + "column": 31 + }, + "end": { + "line": 19, + "column": 32 + } + }, + "name": "b", + "leadingComments": [ + { + "type": "Block", + "value": " " ", + "start": 743, + "end": 755 + } + ] + } + } + ] + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } + }, + { + "type": "Text", + "start": 766, + "end": 767, + "raw": "\n", + "data": "\n" + }, + { + "type": "RegularElement", + "start": 767, + "end": 803, + "name": "div", + "name_loc": { + "start": { + "line": 20, + "column": 1, + "character": 768 + }, + "end": { + "line": 20, + "column": 4, + "character": 771 + } + }, + "attributes": [ + { + "type": "Attribute", + "start": 772, + "end": 796, + "name": "title", + "name_loc": { + "start": { + "line": 20, + "column": 5, + "character": 772 + }, + "end": { + "line": 20, + "column": 10, + "character": 777 + } + }, + "value": [ + { + "start": 779, + "end": 784, + "type": "Text", + "raw": "text1", + "data": "text1" + }, + { + "type": "ExpressionTag", + "start": 784, + "end": 795, + "expression": { + "type": "Identifier", + "start": 793, + "end": 794, + "loc": { + "start": { + "line": 20, + "column": 26 + }, + "end": { + "line": 20, + "column": 27 + } + }, + "name": "b", + "leadingComments": [ + { + "type": "Block", + "value": " ` ", + "start": 785, + "end": 792 + } + ] + } + } + ] + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } + }, + { + "type": "Text", + "start": 803, + "end": 805, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "Comment", + "start": 805, + "end": 881, + "data": " line comment inside a multi-line expression, holding each delimiter " + }, + { + "type": "Text", + "start": 881, + "end": 882, + "raw": "\n", + "data": "\n" + }, + { + "type": "RegularElement", + "start": 882, + "end": 933, + "name": "div", + "name_loc": { + "start": { + "line": 23, + "column": 1, + "character": 883 + }, + "end": { + "line": 23, + "column": 4, + "character": 886 + } + }, + "attributes": [ + { + "type": "Attribute", + "start": 888, + "end": 925, + "name": "title", + "name_loc": { + "start": { + "line": 24, + "column": 1, + "character": 888 + }, + "end": { + "line": 24, + "column": 6, + "character": 893 + } + }, + "value": [ + { + "start": 895, + "end": 900, + "type": "Text", + "raw": "text1", + "data": "text1" + }, + { + "type": "ExpressionTag", + "start": 900, + "end": 924, + "expression": { + "type": "CallExpression", + "start": 901, + "end": 923, + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 27, + "column": 2 + } + }, + "callee": { + "type": "Identifier", + "start": 901, + "end": 902, + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 24, + "column": 15 + } + }, + "name": "f" + }, + "arguments": [ + { + "type": "Identifier", + "start": 919, + "end": 920, + "loc": { + "start": { + "line": 26, + "column": 2 + }, + "end": { + "line": 26, + "column": 3 + } + }, + "name": "b", + "leadingComments": [ + { + "type": "Line", + "value": " ` ' { }", + "start": 906, + "end": 916 + } + ] + } + ], + "optional": false + } + } + ] + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } + }, + { + "type": "Text", + "start": 933, + "end": 935, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "Comment", + "start": 935, + "end": 1022, + "data": " regex containing the attribute's own quote, or one that would open a JS string " + }, + { + "type": "Text", + "start": 1022, + "end": 1023, + "raw": "\n", + "data": "\n" + }, + { + "type": "RegularElement", + "start": 1023, + "end": 1061, + "name": "div", + "name_loc": { + "start": { + "line": 31, + "column": 1, + "character": 1024 + }, + "end": { + "line": 31, + "column": 4, + "character": 1027 + } + }, + "attributes": [ + { + "type": "Attribute", + "start": 1028, + "end": 1054, + "name": "title", + "name_loc": { + "start": { + "line": 31, + "column": 5, + "character": 1028 + }, + "end": { + "line": 31, + "column": 10, + "character": 1033 + } + }, + "value": [ + { + "start": 1035, + "end": 1040, + "type": "Text", + "raw": "text1", + "data": "text1" + }, + { + "type": "ExpressionTag", + "start": 1040, + "end": 1053, + "expression": { + "type": "CallExpression", + "start": 1041, + "end": 1052, + "loc": { + "start": { + "line": 31, + "column": 18 + }, + "end": { + "line": 31, + "column": 29 + } + }, + "callee": { + "type": "Identifier", + "start": 1041, + "end": 1042, + "loc": { + "start": { + "line": 31, + "column": 18 + }, + "end": { + "line": 31, + "column": 19 + } + }, + "name": "f" + }, + "arguments": [ + { + "type": "Literal", + "start": 1043, + "end": 1051, + "loc": { + "start": { + "line": 31, + "column": 20 + }, + "end": { + "line": 31, + "column": 28 + } + }, + "value": {}, + "raw": "/"/", + "regex": { + "pattern": """, + "flags": "" + } + } + ], + "optional": false + } + } + ] + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } + }, + { + "type": "Text", + "start": 1061, + "end": 1062, + "raw": "\n", + "data": "\n" + }, + { + "type": "RegularElement", + "start": 1062, + "end": 1095, + "name": "div", + "name_loc": { + "start": { + "line": 32, + "column": 1, + "character": 1063 + }, + "end": { + "line": 32, + "column": 4, + "character": 1066 + } + }, + "attributes": [ + { + "type": "Attribute", + "start": 1067, + "end": 1088, + "name": "title", + "name_loc": { + "start": { + "line": 32, + "column": 5, + "character": 1067 + }, + "end": { + "line": 32, + "column": 10, + "character": 1072 + } + }, + "value": [ + { + "start": 1074, + "end": 1079, + "type": "Text", + "raw": "text1", + "data": "text1" + }, + { + "type": "ExpressionTag", + "start": 1079, + "end": 1087, + "expression": { + "type": "CallExpression", + "start": 1080, + "end": 1086, + "loc": { + "start": { + "line": 32, + "column": 18 + }, + "end": { + "line": 32, + "column": 24 + } + }, + "callee": { + "type": "Identifier", + "start": 1080, + "end": 1081, + "loc": { + "start": { + "line": 32, + "column": 18 + }, + "end": { + "line": 32, + "column": 19 + } + }, + "name": "f" + }, + "arguments": [ + { + "type": "Literal", + "start": 1082, + "end": 1085, + "loc": { + "start": { + "line": 32, + "column": 20 + }, + "end": { + "line": 32, + "column": 23 + } + }, + "value": {}, + "raw": "/'/", + "regex": { + "pattern": "'", + "flags": "" + } + } + ], + "optional": false + } + } + ] + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } + }, + { + "type": "Text", + "start": 1095, + "end": 1096, + "raw": "\n", + "data": "\n" + }, + { + "type": "RegularElement", + "start": 1096, + "end": 1129, + "name": "div", + "name_loc": { + "start": { + "line": 33, + "column": 1, + "character": 1097 + }, + "end": { + "line": 33, + "column": 4, + "character": 1100 + } + }, + "attributes": [ + { + "type": "Attribute", + "start": 1101, + "end": 1122, + "name": "title", + "name_loc": { + "start": { + "line": 33, + "column": 5, + "character": 1101 + }, + "end": { + "line": 33, + "column": 10, + "character": 1106 + } + }, + "value": [ + { + "start": 1108, + "end": 1113, + "type": "Text", + "raw": "text1", + "data": "text1" + }, + { + "type": "ExpressionTag", + "start": 1113, + "end": 1121, + "expression": { + "type": "CallExpression", + "start": 1114, + "end": 1120, + "loc": { + "start": { + "line": 33, + "column": 18 + }, + "end": { + "line": 33, + "column": 24 + } + }, + "callee": { + "type": "Identifier", + "start": 1114, + "end": 1115, + "loc": { + "start": { + "line": 33, + "column": 18 + }, + "end": { + "line": 33, + "column": 19 + } + }, + "name": "f" + }, + "arguments": [ + { + "type": "Literal", + "start": 1116, + "end": 1119, + "loc": { + "start": { + "line": 33, + "column": 20 + }, + "end": { + "line": 33, + "column": 23 + } + }, + "value": {}, + "raw": "/`/", + "regex": { + "pattern": "`", + "flags": "" + } + } + ], + "optional": false + } + } + ] + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } + }, + { + "type": "Text", + "start": 1129, + "end": 1131, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "Comment", + "start": 1131, + "end": 1210, + "data": " template literal interpolating an expression that holds each delimiter " + }, + { + "type": "Text", + "start": 1210, + "end": 1211, + "raw": "\n", + "data": "\n" + }, + { + "type": "RegularElement", + "start": 1211, + "end": 1260, + "name": "div", + "name_loc": { + "start": { + "line": 36, + "column": 1, + "character": 1212 + }, + "end": { + "line": 36, + "column": 4, + "character": 1215 + } + }, + "attributes": [ + { + "type": "Attribute", + "start": 1216, + "end": 1253, + "name": "title", + "name_loc": { + "start": { + "line": 36, + "column": 5, + "character": 1216 + }, + "end": { + "line": 36, + "column": 10, + "character": 1221 + } + }, + "value": [ + { + "start": 1223, + "end": 1228, + "type": "Text", + "raw": "text1", + "data": "text1" + }, + { + "type": "ExpressionTag", + "start": 1228, + "end": 1252, + "expression": { + "type": "TemplateLiteral", + "start": 1229, + "end": 1251, + "loc": { + "start": { + "line": 36, + "column": 18 + }, + "end": { + "line": 36, + "column": 40 + } + }, + "expressions": [ + { + "type": "CallExpression", + "start": 1232, + "end": 1249, + "loc": { + "start": { + "line": 36, + "column": 21 + }, + "end": { + "line": 36, + "column": 38 + } + }, + "callee": { + "type": "Identifier", + "start": 1232, + "end": 1233, + "loc": { + "start": { + "line": 36, + "column": 21 + }, + "end": { + "line": 36, + "column": 22 + } + }, + "name": "f" + }, + "arguments": [ + { + "type": "Literal", + "start": 1234, + "end": 1248, + "loc": { + "start": { + "line": 36, + "column": 23 + }, + "end": { + "line": 36, + "column": 37 + } + }, + "value": {}, + "raw": "/[{}`'"]/", + "regex": { + "pattern": "[{}`'"]", + "flags": "" + } + } + ], + "optional": false + } + ], + "quasis": [ + { + "type": "TemplateElement", + "start": 1230, + "end": 1230, + "loc": { + "start": { + "line": 36, + "column": 19 + }, + "end": { + "line": 36, + "column": 19 + } + }, + "value": { + "raw": "", + "cooked": "" + }, + "tail": false + }, + { + "type": "TemplateElement", + "start": 1250, + "end": 1250, + "loc": { + "start": { + "line": 36, + "column": 39 + }, + "end": { + "line": 36, + "column": 39 + } + }, + "value": { + "raw": "", + "cooked": "" + }, + "tail": true + } + ] + } + } + ] + } + ], + "fragment": { + "type": "Fragment", + "nodes": [] + } } ] }, @@ -542,6 +1607,86 @@ "column": 25 } } + }, + { + "type": "Block", + "value": " { ", + "start": 527, + "end": 534, + "loc": { + "start": { + "line": 14, + "column": 18 + }, + "end": { + "line": 14, + "column": 25 + } + } + }, + { + "type": "Block", + "value": " ' ", + "start": 706, + "end": 713, + "loc": { + "start": { + "line": 18, + "column": 18 + }, + "end": { + "line": 18, + "column": 25 + } + } + }, + { + "type": "Block", + "value": " " ", + "start": 743, + "end": 755, + "loc": { + "start": { + "line": 19, + "column": 18 + }, + "end": { + "line": 19, + "column": 30 + } + } + }, + { + "type": "Block", + "value": " ` ", + "start": 785, + "end": 792, + "loc": { + "start": { + "line": 20, + "column": 18 + }, + "end": { + "line": 20, + "column": 25 + } + } + }, + { + "type": "Line", + "value": " ` ' { }", + "start": 906, + "end": 916, + "loc": { + "start": { + "line": 25, + "column": 2 + }, + "end": { + "line": 25, + "column": 12 + } + } } ] } diff --git a/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/input.svelte b/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/input.svelte index a2394fc3a..a47e2ea2f 100644 --- a/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/input.svelte +++ b/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/input.svelte @@ -9,3 +9,28 @@
+ + +
+ + +
+
+
+ + +
+ + +
+
+
+ + +
diff --git a/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/unformatted_unquoted.svelte b/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/unformatted_unquoted.svelte index 672fdeb79..d828b1b97 100644 --- a/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/unformatted_unquoted.svelte +++ b/tests/fixtures/svelte/attributes/expression_brace_in_regex_comment/unformatted_unquoted.svelte @@ -9,3 +9,26 @@
+ + +
+ + +
+
+
+ + +
+ + +
+
+
+ + +
diff --git a/tests/fixtures/typescript/expressions/arrays/element_glued_block_comment/expected.json b/tests/fixtures/typescript/expressions/arrays/element_glued_block_comment/expected.json new file mode 100644 index 000000000..6e3db8199 --- /dev/null +++ b/tests/fixtures/typescript/expressions/arrays/element_glued_block_comment/expected.json @@ -0,0 +1,929 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 1010, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " A glued pair before the first array element stays glued.", + "start": 20, + "end": 79, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 60 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 95, + "end": 103, + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 4, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 104, + "end": 112, + "loc": { + "start": { + "line": 4, + "column": 11 + }, + "end": { + "line": 4, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " A glued pair between array elements stays glued.", + "start": 220, + "end": 271, + "loc": { + "start": { + "line": 8, + "column": 1 + }, + "end": { + "line": 8, + "column": 52 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 339, + "end": 347, + "loc": { + "start": { + "line": 11, + "column": 2 + }, + "end": { + "line": 11, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 348, + "end": 356, + "loc": { + "start": { + "line": 11, + "column": 11 + }, + "end": { + "line": 11, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " A glued pair after a line comment stays glued.", + "start": 412, + "end": 461, + "loc": { + "start": { + "line": 14, + "column": 1 + }, + "end": { + "line": 14, + "column": 50 + } + } + }, + { + "type": "Line", + "value": " line", + "start": 529, + "end": 536, + "loc": { + "start": { + "line": 17, + "column": 2 + }, + "end": { + "line": 17, + "column": 9 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 539, + "end": 547, + "loc": { + "start": { + "line": 18, + "column": 2 + }, + "end": { + "line": 18, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 548, + "end": 556, + "loc": { + "start": { + "line": 18, + "column": 11 + }, + "end": { + "line": 18, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 614, + "end": 668, + "loc": { + "start": { + "line": 22, + "column": 1 + }, + "end": { + "line": 22, + "column": 55 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 736, + "end": 744, + "loc": { + "start": { + "line": 25, + "column": 2 + }, + "end": { + "line": 25, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 747, + "end": 755, + "loc": { + "start": { + "line": 26, + "column": 2 + }, + "end": { + "line": 26, + "column": 10 + } + } + }, + { + "type": "Line", + "value": " An array pattern takes the pattern printer.", + "start": 813, + "end": 859, + "loc": { + "start": { + "line": 30, + "column": 1 + }, + "end": { + "line": 30, + "column": 47 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 871, + "end": 879, + "loc": { + "start": { + "line": 32, + "column": 2 + }, + "end": { + "line": 32, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 880, + "end": 888, + "loc": { + "start": { + "line": 32, + "column": 11 + }, + "end": { + "line": 32, + "column": 19 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 1009, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 1000, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 35, + "column": 9 + } + }, + "body": [ + { + "type": "VariableDeclaration", + "start": 81, + "end": 217, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 6, + "column": 3 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 87, + "end": 216, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 6, + "column": 2 + } + }, + "id": { + "type": "Identifier", + "start": 87, + "end": 88, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 3, + "column": 8 + } + }, + "name": "a" + }, + "init": { + "type": "ArrayExpression", + "start": 91, + "end": 216, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 6, + "column": 2 + } + }, + "elements": [ + { + "type": "Identifier", + "start": 113, + "end": 161, + "loc": { + "start": { + "line": 4, + "column": 20 + }, + "end": { + "line": 4, + "column": 68 + } + }, + "name": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLong", + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 95, + "end": 103 + }, + { + "type": "Block", + "value": " c2 ", + "start": 104, + "end": 112 + } + ] + }, + { + "type": "Identifier", + "start": 165, + "end": 213, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 50 + } + }, + "name": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLong" + } + ] + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair before the first array element stays glued.", + "start": 20, + "end": 79 + } + ] + }, + { + "type": "VariableDeclaration", + "start": 273, + "end": 409, + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 12, + "column": 3 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 279, + "end": 408, + "loc": { + "start": { + "line": 9, + "column": 7 + }, + "end": { + "line": 12, + "column": 2 + } + }, + "id": { + "type": "Identifier", + "start": 279, + "end": 280, + "loc": { + "start": { + "line": 9, + "column": 7 + }, + "end": { + "line": 9, + "column": 8 + } + }, + "name": "b" + }, + "init": { + "type": "ArrayExpression", + "start": 283, + "end": 408, + "loc": { + "start": { + "line": 9, + "column": 11 + }, + "end": { + "line": 12, + "column": 2 + } + }, + "elements": [ + { + "type": "Identifier", + "start": 287, + "end": 335, + "loc": { + "start": { + "line": 10, + "column": 2 + }, + "end": { + "line": 10, + "column": 50 + } + }, + "name": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLong" + }, + { + "type": "Identifier", + "start": 357, + "end": 405, + "loc": { + "start": { + "line": 11, + "column": 20 + }, + "end": { + "line": 11, + "column": 68 + } + }, + "name": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLong", + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 339, + "end": 347 + }, + { + "type": "Block", + "value": " c2 ", + "start": 348, + "end": 356 + } + ] + } + ] + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair between array elements stays glued.", + "start": 220, + "end": 271 + } + ] + }, + { + "type": "VariableDeclaration", + "start": 463, + "end": 611, + "loc": { + "start": { + "line": 15, + "column": 1 + }, + "end": { + "line": 20, + "column": 3 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 469, + "end": 610, + "loc": { + "start": { + "line": 15, + "column": 7 + }, + "end": { + "line": 20, + "column": 2 + } + }, + "id": { + "type": "Identifier", + "start": 469, + "end": 470, + "loc": { + "start": { + "line": 15, + "column": 7 + }, + "end": { + "line": 15, + "column": 8 + } + }, + "name": "c" + }, + "init": { + "type": "ArrayExpression", + "start": 473, + "end": 610, + "loc": { + "start": { + "line": 15, + "column": 11 + }, + "end": { + "line": 20, + "column": 2 + } + }, + "elements": [ + { + "type": "Identifier", + "start": 477, + "end": 525, + "loc": { + "start": { + "line": 16, + "column": 2 + }, + "end": { + "line": 16, + "column": 50 + } + }, + "name": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLong" + }, + { + "type": "Identifier", + "start": 559, + "end": 607, + "loc": { + "start": { + "line": 19, + "column": 2 + }, + "end": { + "line": 19, + "column": 50 + } + }, + "name": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLong", + "leadingComments": [ + { + "type": "Line", + "value": " line", + "start": 529, + "end": 536 + }, + { + "type": "Block", + "value": " c1 ", + "start": 539, + "end": 547 + }, + { + "type": "Block", + "value": " c2 ", + "start": 548, + "end": 556 + } + ] + } + ] + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair after a line comment stays glued.", + "start": 412, + "end": 461 + } + ] + }, + { + "type": "VariableDeclaration", + "start": 670, + "end": 810, + "loc": { + "start": { + "line": 23, + "column": 1 + }, + "end": { + "line": 28, + "column": 3 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 676, + "end": 809, + "loc": { + "start": { + "line": 23, + "column": 7 + }, + "end": { + "line": 28, + "column": 2 + } + }, + "id": { + "type": "Identifier", + "start": 676, + "end": 677, + "loc": { + "start": { + "line": 23, + "column": 7 + }, + "end": { + "line": 23, + "column": 8 + } + }, + "name": "d" + }, + "init": { + "type": "ArrayExpression", + "start": 680, + "end": 809, + "loc": { + "start": { + "line": 23, + "column": 11 + }, + "end": { + "line": 28, + "column": 2 + } + }, + "elements": [ + { + "type": "Identifier", + "start": 684, + "end": 732, + "loc": { + "start": { + "line": 24, + "column": 2 + }, + "end": { + "line": 24, + "column": 50 + } + }, + "name": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLong" + }, + { + "type": "Identifier", + "start": 758, + "end": 806, + "loc": { + "start": { + "line": 27, + "column": 2 + }, + "end": { + "line": 27, + "column": 50 + } + }, + "name": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLong", + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 736, + "end": 744 + }, + { + "type": "Block", + "value": " c2 ", + "start": 747, + "end": 755 + } + ] + } + ] + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 614, + "end": 668 + } + ] + }, + { + "type": "VariableDeclaration", + "start": 861, + "end": 999, + "loc": { + "start": { + "line": 31, + "column": 1 + }, + "end": { + "line": 34, + "column": 9 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 867, + "end": 998, + "loc": { + "start": { + "line": 31, + "column": 7 + }, + "end": { + "line": 34, + "column": 8 + } + }, + "id": { + "type": "ArrayPattern", + "start": 867, + "end": 992, + "loc": { + "start": { + "line": 31, + "column": 7 + }, + "end": { + "line": 34, + "column": 2 + } + }, + "elements": [ + { + "type": "Identifier", + "start": 889, + "end": 937, + "loc": { + "start": { + "line": 32, + "column": 20 + }, + "end": { + "line": 32, + "column": 68 + } + }, + "name": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeLong", + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 871, + "end": 879 + }, + { + "type": "Block", + "value": " c2 ", + "start": 880, + "end": 888 + } + ] + }, + { + "type": "Identifier", + "start": 941, + "end": 989, + "loc": { + "start": { + "line": 33, + "column": 2 + }, + "end": { + "line": 33, + "column": 50 + } + }, + "name": "ffffffffffffffffffffffffffffffffffffffffffffLong" + } + ] + }, + "init": { + "type": "Identifier", + "start": 995, + "end": 998, + "loc": { + "start": { + "line": 34, + "column": 5 + }, + "end": { + "line": 34, + "column": 8 + } + }, + "name": "arr" + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " An array pattern takes the pattern printer.", + "start": 813, + "end": 859 + } + ] + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/expressions/arrays/element_glued_block_comment/input.svelte b/tests/fixtures/typescript/expressions/arrays/element_glued_block_comment/input.svelte new file mode 100644 index 000000000..c461e9aa5 --- /dev/null +++ b/tests/fixtures/typescript/expressions/arrays/element_glued_block_comment/input.svelte @@ -0,0 +1,35 @@ + diff --git a/tests/fixtures/typescript/expressions/arrays/element_glued_block_comment/unformatted_glued_run_own_line.svelte b/tests/fixtures/typescript/expressions/arrays/element_glued_block_comment/unformatted_glued_run_own_line.svelte new file mode 100644 index 000000000..92fd4fb97 --- /dev/null +++ b/tests/fixtures/typescript/expressions/arrays/element_glued_block_comment/unformatted_glued_run_own_line.svelte @@ -0,0 +1,38 @@ + diff --git a/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/expected.json b/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/expected.json index 3b119445e..2c205b49e 100644 --- a/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/expected.json +++ b/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/expected.json @@ -2,7 +2,7 @@ "css": null, "js": [], "start": 0, - "end": 978, + "end": 1122, "type": "Root", "fragment": { "type": "Fragment", @@ -236,9 +236,9 @@ }, { "type": "Line", - "value": " A newline after the comment unglues it - the comment takes its own line", + "value": " A newline after the comment is ours to reflow - it lands on the element's line,", "start": 678, - "end": 752, + "end": 760, "loc": { "start": { "line": 29, @@ -246,22 +246,54 @@ }, "end": { "line": 29, - "column": 75 + "column": 83 + } + } + }, + { + "type": "Line", + "value": " the same fixed point the glued authoring reaches (e), and matching the inline", + "start": 762, + "end": 842, + "loc": { + "start": { + "line": 30, + "column": 1 + }, + "end": { + "line": 30, + "column": 81 + } + } + }, + { + "type": "Line", + "value": " cases above, which collapse the identical authoring", + "start": 844, + "end": 898, + "loc": { + "start": { + "line": 31, + "column": 1 + }, + "end": { + "line": 31, + "column": 55 } } }, { "type": "Block", "value": " c1 ", - "start": 778, - "end": 786, + "start": 924, + "end": 932, "loc": { "start": { - "line": 32, + "line": 34, "column": 2 }, "end": { - "line": 32, + "line": 34, "column": 10 } } @@ -269,31 +301,31 @@ { "type": "Line", "value": " c2", - "start": 797, - "end": 802, + "start": 941, + "end": 946, "loc": { "start": { - "line": 33, - "column": 10 + "line": 34, + "column": 19 }, "end": { - "line": 33, - "column": 15 + "line": 34, + "column": 24 } } }, { "type": "Line", "value": " A blank line after the comment - it takes its own line and the blank line survives", - "start": 818, - "end": 903, + "start": 962, + "end": 1047, "loc": { "start": { - "line": 37, + "line": 38, "column": 1 }, "end": { - "line": 37, + "line": 38, "column": 86 } } @@ -301,15 +333,15 @@ { "type": "Block", "value": " c1 ", - "start": 929, - "end": 937, + "start": 1073, + "end": 1081, "loc": { "start": { - "line": 40, + "line": 41, "column": 2 }, "end": { - "line": 40, + "line": 41, "column": 10 } } @@ -317,15 +349,15 @@ { "type": "Line", "value": " c2", - "start": 949, - "end": 954, + "start": 1093, + "end": 1098, "loc": { "start": { - "line": 42, + "line": 43, "column": 10 }, "end": { - "line": 42, + "line": 43, "column": 15 } } @@ -334,19 +366,19 @@ "instance": { "type": "Script", "start": 0, - "end": 977, + "end": 1121, "context": "default", "content": { "type": "Program", "start": 8, - "end": 968, + "end": 1112, "loc": { "start": { "line": 1, "column": 0 }, "end": { - "line": 45, + "line": 46, "column": 9 } }, @@ -1188,44 +1220,44 @@ }, { "type": "VariableDeclaration", - "start": 754, - "end": 815, + "start": 900, + "end": 959, "loc": { "start": { - "line": 30, + "line": 32, "column": 1 }, "end": { - "line": 35, + "line": 36, "column": 3 } }, "declarations": [ { "type": "VariableDeclarator", - "start": 760, - "end": 814, + "start": 906, + "end": 958, "loc": { "start": { - "line": 30, + "line": 32, "column": 7 }, "end": { - "line": 35, + "line": 36, "column": 2 } }, "id": { "type": "Identifier", - "start": 760, - "end": 761, + "start": 906, + "end": 907, "loc": { "start": { - "line": 30, + "line": 32, "column": 7 }, "end": { - "line": 30, + "line": 32, "column": 8 } }, @@ -1233,30 +1265,30 @@ }, "init": { "type": "ArrayExpression", - "start": 764, - "end": 814, + "start": 910, + "end": 958, "loc": { "start": { - "line": 30, + "line": 32, "column": 11 }, "end": { - "line": 35, + "line": 36, "column": 2 } }, "elements": [ { "type": "Literal", - "start": 768, - "end": 774, + "start": 914, + "end": 920, "loc": { "start": { - "line": 31, + "line": 33, "column": 2 }, "end": { - "line": 31, + "line": 33, "column": 8 } }, @@ -1265,16 +1297,16 @@ }, { "type": "Literal", - "start": 789, - "end": 795, + "start": 933, + "end": 939, "loc": { "start": { - "line": 33, - "column": 2 + "line": 34, + "column": 11 }, "end": { - "line": 33, - "column": 8 + "line": 34, + "column": 17 } }, "value": "bbbb", @@ -1283,30 +1315,30 @@ { "type": "Block", "value": " c1 ", - "start": 778, - "end": 786 + "start": 924, + "end": 932 } ], "trailingComments": [ { "type": "Line", "value": " c2", - "start": 797, - "end": 802 + "start": 941, + "end": 946 } ] }, { "type": "Literal", - "start": 805, - "end": 811, + "start": 949, + "end": 955, "loc": { "start": { - "line": 34, + "line": 35, "column": 2 }, "end": { - "line": 34, + "line": 35, "column": 8 } }, @@ -1321,52 +1353,64 @@ "leadingComments": [ { "type": "Line", - "value": " A newline after the comment unglues it - the comment takes its own line", + "value": " A newline after the comment is ours to reflow - it lands on the element's line,", "start": 678, - "end": 752 + "end": 760 + }, + { + "type": "Line", + "value": " the same fixed point the glued authoring reaches (e), and matching the inline", + "start": 762, + "end": 842 + }, + { + "type": "Line", + "value": " cases above, which collapse the identical authoring", + "start": 844, + "end": 898 } ] }, { "type": "VariableDeclaration", - "start": 905, - "end": 967, + "start": 1049, + "end": 1111, "loc": { "start": { - "line": 38, + "line": 39, "column": 1 }, "end": { - "line": 44, + "line": 45, "column": 3 } }, "declarations": [ { "type": "VariableDeclarator", - "start": 911, - "end": 966, + "start": 1055, + "end": 1110, "loc": { "start": { - "line": 38, + "line": 39, "column": 7 }, "end": { - "line": 44, + "line": 45, "column": 2 } }, "id": { "type": "Identifier", - "start": 911, - "end": 912, + "start": 1055, + "end": 1056, "loc": { "start": { - "line": 38, + "line": 39, "column": 7 }, "end": { - "line": 38, + "line": 39, "column": 8 } }, @@ -1374,30 +1418,30 @@ }, "init": { "type": "ArrayExpression", - "start": 915, - "end": 966, + "start": 1059, + "end": 1110, "loc": { "start": { - "line": 38, + "line": 39, "column": 11 }, "end": { - "line": 44, + "line": 45, "column": 2 } }, "elements": [ { "type": "Literal", - "start": 919, - "end": 925, + "start": 1063, + "end": 1069, "loc": { "start": { - "line": 39, + "line": 40, "column": 2 }, "end": { - "line": 39, + "line": 40, "column": 8 } }, @@ -1406,15 +1450,15 @@ }, { "type": "Literal", - "start": 941, - "end": 947, + "start": 1085, + "end": 1091, "loc": { "start": { - "line": 42, + "line": 43, "column": 2 }, "end": { - "line": 42, + "line": 43, "column": 8 } }, @@ -1424,30 +1468,30 @@ { "type": "Block", "value": " c1 ", - "start": 929, - "end": 937 + "start": 1073, + "end": 1081 } ], "trailingComments": [ { "type": "Line", "value": " c2", - "start": 949, - "end": 954 + "start": 1093, + "end": 1098 } ] }, { "type": "Literal", - "start": 957, - "end": 963, + "start": 1101, + "end": 1107, "loc": { "start": { - "line": 43, + "line": 44, "column": 2 }, "end": { - "line": 43, + "line": 44, "column": 8 } }, @@ -1463,8 +1507,8 @@ { "type": "Line", "value": " A blank line after the comment - it takes its own line and the blank line survives", - "start": 818, - "end": 903 + "start": 962, + "end": 1047 } ] } diff --git a/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/input.svelte b/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/input.svelte index 8a9fddeea..ff15c7fe9 100644 --- a/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/input.svelte +++ b/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/input.svelte @@ -26,11 +26,12 @@ 'cccc' ]; - // A newline after the comment unglues it - the comment takes its own line + // A newline after the comment is ours to reflow - it lands on the element's line, + // the same fixed point the glued authoring reaches (e), and matching the inline + // cases above, which collapse the identical authoring const g = [ 'aaaa', - /* c1 */ - 'bbbb', // c2 + /* c1 */ 'bbbb', // c2 'cccc' ]; diff --git a/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/unformatted_ours_newline_after.svelte b/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/unformatted_ours_newline_after.svelte index 572a8761c..d7d94815a 100644 --- a/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/unformatted_ours_newline_after.svelte +++ b/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/unformatted_ours_newline_after.svelte @@ -23,7 +23,9 @@ const f = ['aaaa', /* c1 */ 'bbbb', // c2 , 'cccc']; - // A newline after the comment unglues it - the comment takes its own line + // A newline after the comment is ours to reflow - it lands on the element's line, + // the same fixed point the glued authoring reaches (e), and matching the inline + // cases above, which collapse the identical authoring const g = ['aaaa', /* c1 */ 'bbbb', // c2 'cccc']; diff --git a/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/variant_before_comma.svelte b/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/variant_before_comma.svelte index 529203d05..daf47343c 100644 --- a/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/variant_before_comma.svelte +++ b/tests/fixtures/typescript/expressions/arrays/end_of_line_block_comment_prettier_divergence/variant_before_comma.svelte @@ -26,7 +26,9 @@ 'cccc' ]; - // A newline after the comment unglues it - the comment takes its own line + // A newline after the comment is ours to reflow - it lands on the element's line, + // the same fixed point the glued authoring reaches (e), and matching the inline + // cases above, which collapse the identical authoring const g = [ 'aaaa' /* c1 */, 'bbbb', // c2 diff --git a/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/README.md b/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/README.md new file mode 100644 index 000000000..ba9d02424 --- /dev/null +++ b/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/README.md @@ -0,0 +1,32 @@ +# computed_index_glued_block_comment_prettier_divergence + +A run of block comments leading a computed member-access index (`obj[idx]`, and the optional +`obj?.[idx]`), in the bracket-break path (a line comment in an in-bracket gap is the only +trigger — an element access never breaks on width). + +The **run itself follows prettier's rule**: a pair the author glued stays glued and the index +breaks below (`a`, `c`), and blocks the author put on their own lines keep them (`b`) — that is +prettier's `printLeadingComment`, applied through tsv's one shared leading-comment emitter. + +## The divergence + +Prettier empties the brackets: it hoists the whole in-bracket comment run *out* to before the +object, and strands the `[`-line comment between the object and its own index — + +```ts +const a = + /* c1 */ /* c2 */ + obj // force + [idx]; +``` + +Every comment changes what it reads as being about. `c1`/`c2` were written about `idx` and now +lead the entire expression; `// force` sat on the `[` and now trails `obj`. Splitting `obj` +from `[idx]` across a line is itself gratuitous. tsv keeps all three where the author put them, +inside the brackets they were written in. + +This is the open-delimiter trailing-comment divergence (the `[`-line comment) plus the +computed-member hoist, both sanctioned; the optional `?.[` form takes the same path and shows +the same relocation. + +See [conformance_prettier.md §Comment relocation](../../../../../../docs/conformance_prettier.md#comment-relocation). diff --git a/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/expected.json b/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/expected.json new file mode 100644 index 000000000..d1fce659d --- /dev/null +++ b/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/expected.json @@ -0,0 +1,652 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 366, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " A glued pair of blocks after the `[`-line comment stays glued.", + "start": 20, + "end": 85, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 66 + } + } + }, + { + "type": "Line", + "value": " force", + "start": 102, + "end": 110, + "loc": { + "start": { + "line": 3, + "column": 16 + }, + "end": { + "line": 3, + "column": 24 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 113, + "end": 121, + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 4, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 122, + "end": 130, + "loc": { + "start": { + "line": 4, + "column": 11 + }, + "end": { + "line": 4, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 143, + "end": 197, + "loc": { + "start": { + "line": 8, + "column": 1 + }, + "end": { + "line": 8, + "column": 55 + } + } + }, + { + "type": "Line", + "value": " force", + "start": 214, + "end": 222, + "loc": { + "start": { + "line": 9, + "column": 16 + }, + "end": { + "line": 9, + "column": 24 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 225, + "end": 233, + "loc": { + "start": { + "line": 10, + "column": 2 + }, + "end": { + "line": 10, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 236, + "end": 244, + "loc": { + "start": { + "line": 11, + "column": 2 + }, + "end": { + "line": 11, + "column": 10 + } + } + }, + { + "type": "Line", + "value": " The optional form takes the same path.", + "start": 257, + "end": 298, + "loc": { + "start": { + "line": 15, + "column": 1 + }, + "end": { + "line": 15, + "column": 42 + } + } + }, + { + "type": "Line", + "value": " force", + "start": 317, + "end": 325, + "loc": { + "start": { + "line": 16, + "column": 18 + }, + "end": { + "line": 16, + "column": 26 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 328, + "end": 336, + "loc": { + "start": { + "line": 17, + "column": 2 + }, + "end": { + "line": 17, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 337, + "end": 345, + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 17, + "column": 19 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 365, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 356, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 20, + "column": 9 + } + }, + "body": [ + { + "type": "VariableDeclaration", + "start": 87, + "end": 140, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 6, + "column": 3 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 93, + "end": 139, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 6, + "column": 2 + } + }, + "id": { + "type": "Identifier", + "start": 93, + "end": 94, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 3, + "column": 8 + } + }, + "name": "a" + }, + "init": { + "type": "MemberExpression", + "start": 97, + "end": 139, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 6, + "column": 2 + } + }, + "object": { + "type": "Identifier", + "start": 97, + "end": 100, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 3, + "column": 14 + } + }, + "name": "obj" + }, + "property": { + "type": "Identifier", + "start": 133, + "end": 136, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "name": "idx", + "leadingComments": [ + { + "type": "Line", + "value": " force", + "start": 102, + "end": 110 + }, + { + "type": "Block", + "value": " c1 ", + "start": 113, + "end": 121 + }, + { + "type": "Block", + "value": " c2 ", + "start": 122, + "end": 130 + } + ] + }, + "computed": true, + "optional": false + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair of blocks after the `[`-line comment stays glued.", + "start": 20, + "end": 85 + } + ] + }, + { + "type": "VariableDeclaration", + "start": 199, + "end": 254, + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 13, + "column": 3 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 205, + "end": 253, + "loc": { + "start": { + "line": 9, + "column": 7 + }, + "end": { + "line": 13, + "column": 2 + } + }, + "id": { + "type": "Identifier", + "start": 205, + "end": 206, + "loc": { + "start": { + "line": 9, + "column": 7 + }, + "end": { + "line": 9, + "column": 8 + } + }, + "name": "b" + }, + "init": { + "type": "MemberExpression", + "start": 209, + "end": 253, + "loc": { + "start": { + "line": 9, + "column": 11 + }, + "end": { + "line": 13, + "column": 2 + } + }, + "object": { + "type": "Identifier", + "start": 209, + "end": 212, + "loc": { + "start": { + "line": 9, + "column": 11 + }, + "end": { + "line": 9, + "column": 14 + } + }, + "name": "obj" + }, + "property": { + "type": "Identifier", + "start": 247, + "end": 250, + "loc": { + "start": { + "line": 12, + "column": 2 + }, + "end": { + "line": 12, + "column": 5 + } + }, + "name": "idx", + "leadingComments": [ + { + "type": "Line", + "value": " force", + "start": 214, + "end": 222 + }, + { + "type": "Block", + "value": " c1 ", + "start": 225, + "end": 233 + }, + { + "type": "Block", + "value": " c2 ", + "start": 236, + "end": 244 + } + ] + }, + "computed": true, + "optional": false + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 143, + "end": 197 + } + ] + }, + { + "type": "VariableDeclaration", + "start": 300, + "end": 355, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 19, + "column": 3 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 306, + "end": 354, + "loc": { + "start": { + "line": 16, + "column": 7 + }, + "end": { + "line": 19, + "column": 2 + } + }, + "id": { + "type": "Identifier", + "start": 306, + "end": 307, + "loc": { + "start": { + "line": 16, + "column": 7 + }, + "end": { + "line": 16, + "column": 8 + } + }, + "name": "c" + }, + "init": { + "type": "ChainExpression", + "start": 310, + "end": 354, + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 19, + "column": 2 + } + }, + "expression": { + "type": "MemberExpression", + "start": 310, + "end": 354, + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 19, + "column": 2 + } + }, + "object": { + "type": "Identifier", + "start": 310, + "end": 313, + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 16, + "column": 14 + } + }, + "name": "obj" + }, + "property": { + "type": "Identifier", + "start": 348, + "end": 351, + "loc": { + "start": { + "line": 18, + "column": 2 + }, + "end": { + "line": 18, + "column": 5 + } + }, + "name": "idx", + "leadingComments": [ + { + "type": "Line", + "value": " force", + "start": 317, + "end": 325 + }, + { + "type": "Block", + "value": " c1 ", + "start": 328, + "end": 336 + }, + { + "type": "Block", + "value": " c2 ", + "start": 337, + "end": 345 + } + ] + }, + "computed": true, + "optional": true + } + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " The optional form takes the same path.", + "start": 257, + "end": 298 + } + ] + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/input.svelte b/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/input.svelte new file mode 100644 index 000000000..ec19c1e76 --- /dev/null +++ b/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/input.svelte @@ -0,0 +1,20 @@ + diff --git a/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/output_prettier.svelte b/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/output_prettier.svelte new file mode 100644 index 000000000..5f1c1ee6a --- /dev/null +++ b/tests/fixtures/typescript/expressions/member/computed_index_glued_block_comment_prettier_divergence/output_prettier.svelte @@ -0,0 +1,20 @@ + diff --git a/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/README.md b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/README.md new file mode 100644 index 000000000..ba8866ebf --- /dev/null +++ b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/README.md @@ -0,0 +1,25 @@ +# computed_key_glued_block_comment_prettier_divergence + +A run of block comments leading an object literal's computed key `[key]`, in the +bracket-break path (a line comment in an in-bracket gap is the only trigger — a computed key +never breaks on width). + +The **run itself follows prettier's rule**: a pair the author glued stays glued and the key +breaks below (`a`), and blocks the author put on their own lines keep them (`b`). That is +prettier's `printLeadingComment`, applied through tsv's one shared leading-comment emitter. + +## The divergence + +Two relocations, neither introduced here, both already sanctioned: + +- the `[`-line comment — tsv keeps `// force` on the `[` line; prettier relocates it out to + the **member's** own leading line (the open-delimiter trailing-comment divergence); +- the in-bracket run — prettier hoists `/* c2 */` out of the brackets entirely + (`/* c2 */⏎[/* c1 */ key]: 1`), splitting a run the author wrote as one unit and re-binding + `c2` from the key to the member. tsv keeps both comments where they were written. + +Note prettier is not self-consistent across the two cases: it hoists `c2` out in `a` but +leaves both inside the brackets in `b` (`[/* c1 */⏎/* c2 */⏎key]`) — the same comments, the +same position, differing only in whether the author glued them. + +See [conformance_prettier.md §Comment relocation](../../../../../../docs/conformance_prettier.md#comment-relocation). diff --git a/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/audit_signature.txt b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/audit_signature.txt new file mode 100644 index 000000000..46ecc8078 --- /dev/null +++ b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/audit_signature.txt @@ -0,0 +1,43 @@ +# Auto-generated prettier chain signature. Do not edit manually. +# Regenerate: deno task fixtures:update:formatted +# +# Each %%PASS=N%% section is exactly prettier^N(output_prettier.). +# This file exists when prettier is non-idempotent on output_prettier.* — it pins +# the full chain so the audit recognizes the case and the validator catches drift. +# See docs/fixture_overview.md (rule F4) and crates/tsv_debug/src/fixtures/audit_signature.rs. + +%%PASS=2%% + + +%%PASS=3 (fixed point)%% + diff --git a/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/expected.json b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/expected.json new file mode 100644 index 000000000..f2dcf1ffb --- /dev/null +++ b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/expected.json @@ -0,0 +1,487 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 286, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " A glued pair of blocks after the `[`-line comment stays glued.", + "start": 20, + "end": 85, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 66 + } + } + }, + { + "type": "Line", + "value": " force", + "start": 103, + "end": 111, + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 12 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 115, + "end": 123, + "loc": { + "start": { + "line": 5, + "column": 3 + }, + "end": { + "line": 5, + "column": 11 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 124, + "end": 132, + "loc": { + "start": { + "line": 5, + "column": 12 + }, + "end": { + "line": 5, + "column": 20 + } + } + }, + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 153, + "end": 207, + "loc": { + "start": { + "line": 10, + "column": 1 + }, + "end": { + "line": 10, + "column": 55 + } + } + }, + { + "type": "Line", + "value": " force", + "start": 225, + "end": 233, + "loc": { + "start": { + "line": 12, + "column": 4 + }, + "end": { + "line": 12, + "column": 12 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 237, + "end": 245, + "loc": { + "start": { + "line": 13, + "column": 3 + }, + "end": { + "line": 13, + "column": 11 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 249, + "end": 257, + "loc": { + "start": { + "line": 14, + "column": 3 + }, + "end": { + "line": 14, + "column": 11 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 285, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 276, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 18, + "column": 9 + } + }, + "body": [ + { + "type": "VariableDeclaration", + "start": 87, + "end": 150, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 8, + "column": 3 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 93, + "end": 149, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 8, + "column": 2 + } + }, + "id": { + "type": "Identifier", + "start": 93, + "end": 94, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 3, + "column": 8 + } + }, + "name": "a" + }, + "init": { + "type": "ObjectExpression", + "start": 97, + "end": 149, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 8, + "column": 2 + } + }, + "properties": [ + { + "type": "Property", + "start": 101, + "end": 146, + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 7, + "column": 6 + } + }, + "method": false, + "shorthand": false, + "computed": true, + "key": { + "type": "Identifier", + "start": 136, + "end": 139, + "loc": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 6 + } + }, + "name": "key", + "leadingComments": [ + { + "type": "Line", + "value": " force", + "start": 103, + "end": 111 + }, + { + "type": "Block", + "value": " c1 ", + "start": 115, + "end": 123 + }, + { + "type": "Block", + "value": " c2 ", + "start": 124, + "end": 132 + } + ] + }, + "value": { + "type": "Literal", + "start": 145, + "end": 146, + "loc": { + "start": { + "line": 7, + "column": 5 + }, + "end": { + "line": 7, + "column": 6 + } + }, + "value": 1, + "raw": "1" + }, + "kind": "init" + } + ] + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair of blocks after the `[`-line comment stays glued.", + "start": 20, + "end": 85 + } + ] + }, + { + "type": "VariableDeclaration", + "start": 209, + "end": 275, + "loc": { + "start": { + "line": 11, + "column": 1 + }, + "end": { + "line": 17, + "column": 3 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 215, + "end": 274, + "loc": { + "start": { + "line": 11, + "column": 7 + }, + "end": { + "line": 17, + "column": 2 + } + }, + "id": { + "type": "Identifier", + "start": 215, + "end": 216, + "loc": { + "start": { + "line": 11, + "column": 7 + }, + "end": { + "line": 11, + "column": 8 + } + }, + "name": "b" + }, + "init": { + "type": "ObjectExpression", + "start": 219, + "end": 274, + "loc": { + "start": { + "line": 11, + "column": 11 + }, + "end": { + "line": 17, + "column": 2 + } + }, + "properties": [ + { + "type": "Property", + "start": 223, + "end": 271, + "loc": { + "start": { + "line": 12, + "column": 2 + }, + "end": { + "line": 16, + "column": 6 + } + }, + "method": false, + "shorthand": false, + "computed": true, + "key": { + "type": "Identifier", + "start": 261, + "end": 264, + "loc": { + "start": { + "line": 15, + "column": 3 + }, + "end": { + "line": 15, + "column": 6 + } + }, + "name": "key", + "leadingComments": [ + { + "type": "Line", + "value": " force", + "start": 225, + "end": 233 + }, + { + "type": "Block", + "value": " c1 ", + "start": 237, + "end": 245 + }, + { + "type": "Block", + "value": " c2 ", + "start": 249, + "end": 257 + } + ] + }, + "value": { + "type": "Literal", + "start": 270, + "end": 271, + "loc": { + "start": { + "line": 16, + "column": 5 + }, + "end": { + "line": 16, + "column": 6 + } + }, + "value": 1, + "raw": "1" + }, + "kind": "init" + } + ] + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 153, + "end": 207 + } + ] + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/input.svelte b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/input.svelte new file mode 100644 index 000000000..ad4e7d890 --- /dev/null +++ b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/input.svelte @@ -0,0 +1,18 @@ + diff --git a/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/output_prettier.svelte b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/output_prettier.svelte new file mode 100644 index 000000000..954f4ef76 --- /dev/null +++ b/tests/fixtures/typescript/expressions/objects/computed_key_glued_block_comment_prettier_divergence/output_prettier.svelte @@ -0,0 +1,16 @@ + diff --git a/tests/fixtures/typescript/expressions/type_assertion/angle_glued_block_comment_prettier_divergence/README.md b/tests/fixtures/typescript/expressions/type_assertion/angle_glued_block_comment_prettier_divergence/README.md new file mode 100644 index 000000000..a56cfdf8c --- /dev/null +++ b/tests/fixtures/typescript/expressions/type_assertion/angle_glued_block_comment_prettier_divergence/README.md @@ -0,0 +1,23 @@ +# angle_glued_block_comment_prettier_divergence + +A run of block comments leading an angle-bracket type assertion's type (`expr`), in the +broken-cast path (a line comment in the `<`→type gap is what forces it). + +`input.ts` rather than `input.svelte`: the angle assertion is TS-only *syntax* that a `.svelte` +` diff --git a/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/README.md b/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/README.md new file mode 100644 index 000000000..4537ab8c0 --- /dev/null +++ b/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/README.md @@ -0,0 +1,19 @@ +# mapped_key_glued_block_comment_prettier_divergence + +A run of block comments leading a mapped type's `[K in keyof T]` key, in the bracket-break +path (a line comment on the `[` line is what forces it). + +The **run itself matches prettier**: a pair the author glued stays glued and the key breaks +below (`A`), and blocks the author put on their own lines keep them (`B`). That is prettier's +`printLeadingComment` — the separator after each comment is read from the source around *that* +comment, never from where the key starts — which tsv applies through its one shared +leading-comment emitter. + +## The divergence + +Only the `[`-line comment, unchanged by this fixture's subject: tsv keeps `// force` on the +`[` line, prettier relocates it to its own line as the key's leading comment. That is the +open-delimiter trailing-comment divergence, sanctioned and cataloged for the mapped-type `[` +among the rest of its family. + +See [conformance_prettier.md §Comment relocation](../../../../../docs/conformance_prettier.md#comment-relocation). diff --git a/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/expected.json b/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/expected.json new file mode 100644 index 000000000..142b782b7 --- /dev/null +++ b/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/expected.json @@ -0,0 +1,625 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 310, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " A glued pair of blocks after the `[`-line comment stays glued.", + "start": 20, + "end": 85, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 66 + } + } + }, + { + "type": "Line", + "value": " force", + "start": 102, + "end": 110, + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 12 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 114, + "end": 122, + "loc": { + "start": { + "line": 5, + "column": 3 + }, + "end": { + "line": 5, + "column": 11 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 123, + "end": 131, + "loc": { + "start": { + "line": 5, + "column": 12 + }, + "end": { + "line": 5, + "column": 20 + } + } + }, + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 165, + "end": 219, + "loc": { + "start": { + "line": 10, + "column": 1 + }, + "end": { + "line": 10, + "column": 55 + } + } + }, + { + "type": "Line", + "value": " force", + "start": 236, + "end": 244, + "loc": { + "start": { + "line": 12, + "column": 4 + }, + "end": { + "line": 12, + "column": 12 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 248, + "end": 256, + "loc": { + "start": { + "line": 13, + "column": 3 + }, + "end": { + "line": 13, + "column": 11 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 260, + "end": 268, + "loc": { + "start": { + "line": 14, + "column": 3 + }, + "end": { + "line": 14, + "column": 11 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 309, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 300, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 18, + "column": 9 + } + }, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start": 87, + "end": 162, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 8, + "column": 3 + } + }, + "id": { + "type": "Identifier", + "start": 92, + "end": 93, + "loc": { + "start": { + "line": 3, + "column": 6 + }, + "end": { + "line": 3, + "column": 7 + } + }, + "name": "A" + }, + "typeAnnotation": { + "type": "TSMappedType", + "start": 96, + "end": 161, + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 8, + "column": 2 + } + }, + "typeParameter": { + "type": "TSTypeParameter", + "start": 135, + "end": 147, + "loc": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 15 + } + }, + "name": "K", + "constraint": { + "type": "TSTypeOperator", + "start": 140, + "end": 147, + "loc": { + "start": { + "line": 6, + "column": 8 + }, + "end": { + "line": 6, + "column": 15 + } + }, + "operator": "keyof", + "typeAnnotation": { + "type": "TSTypeReference", + "start": 146, + "end": 147, + "loc": { + "start": { + "line": 6, + "column": 14 + }, + "end": { + "line": 6, + "column": 15 + } + }, + "typeName": { + "type": "Identifier", + "start": 146, + "end": 147, + "loc": { + "start": { + "line": 6, + "column": 14 + }, + "end": { + "line": 6, + "column": 15 + } + }, + "name": "T" + } + } + }, + "leadingComments": [ + { + "type": "Line", + "value": " force", + "start": 102, + "end": 110 + }, + { + "type": "Block", + "value": " c1 ", + "start": 114, + "end": 122 + }, + { + "type": "Block", + "value": " c2 ", + "start": 123, + "end": 131 + } + ] + }, + "nameType": null, + "typeAnnotation": { + "type": "TSIndexedAccessType", + "start": 153, + "end": 157, + "loc": { + "start": { + "line": 7, + "column": 5 + }, + "end": { + "line": 7, + "column": 9 + } + }, + "objectType": { + "type": "TSTypeReference", + "start": 153, + "end": 154, + "loc": { + "start": { + "line": 7, + "column": 5 + }, + "end": { + "line": 7, + "column": 6 + } + }, + "typeName": { + "type": "Identifier", + "start": 153, + "end": 154, + "loc": { + "start": { + "line": 7, + "column": 5 + }, + "end": { + "line": 7, + "column": 6 + } + }, + "name": "T" + } + }, + "indexType": { + "type": "TSTypeReference", + "start": 155, + "end": 156, + "loc": { + "start": { + "line": 7, + "column": 7 + }, + "end": { + "line": 7, + "column": 8 + } + }, + "typeName": { + "type": "Identifier", + "start": 155, + "end": 156, + "loc": { + "start": { + "line": 7, + "column": 7 + }, + "end": { + "line": 7, + "column": 8 + } + }, + "name": "K" + } + } + } + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair of blocks after the `[`-line comment stays glued.", + "start": 20, + "end": 85 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 221, + "end": 299, + "loc": { + "start": { + "line": 11, + "column": 1 + }, + "end": { + "line": 17, + "column": 3 + } + }, + "id": { + "type": "Identifier", + "start": 226, + "end": 227, + "loc": { + "start": { + "line": 11, + "column": 6 + }, + "end": { + "line": 11, + "column": 7 + } + }, + "name": "B" + }, + "typeAnnotation": { + "type": "TSMappedType", + "start": 230, + "end": 298, + "loc": { + "start": { + "line": 11, + "column": 10 + }, + "end": { + "line": 17, + "column": 2 + } + }, + "typeParameter": { + "type": "TSTypeParameter", + "start": 272, + "end": 284, + "loc": { + "start": { + "line": 15, + "column": 3 + }, + "end": { + "line": 15, + "column": 15 + } + }, + "name": "K", + "constraint": { + "type": "TSTypeOperator", + "start": 277, + "end": 284, + "loc": { + "start": { + "line": 15, + "column": 8 + }, + "end": { + "line": 15, + "column": 15 + } + }, + "operator": "keyof", + "typeAnnotation": { + "type": "TSTypeReference", + "start": 283, + "end": 284, + "loc": { + "start": { + "line": 15, + "column": 14 + }, + "end": { + "line": 15, + "column": 15 + } + }, + "typeName": { + "type": "Identifier", + "start": 283, + "end": 284, + "loc": { + "start": { + "line": 15, + "column": 14 + }, + "end": { + "line": 15, + "column": 15 + } + }, + "name": "T" + } + } + }, + "leadingComments": [ + { + "type": "Line", + "value": " force", + "start": 236, + "end": 244 + }, + { + "type": "Block", + "value": " c1 ", + "start": 248, + "end": 256 + }, + { + "type": "Block", + "value": " c2 ", + "start": 260, + "end": 268 + } + ] + }, + "nameType": null, + "typeAnnotation": { + "type": "TSIndexedAccessType", + "start": 290, + "end": 294, + "loc": { + "start": { + "line": 16, + "column": 5 + }, + "end": { + "line": 16, + "column": 9 + } + }, + "objectType": { + "type": "TSTypeReference", + "start": 290, + "end": 291, + "loc": { + "start": { + "line": 16, + "column": 5 + }, + "end": { + "line": 16, + "column": 6 + } + }, + "typeName": { + "type": "Identifier", + "start": 290, + "end": 291, + "loc": { + "start": { + "line": 16, + "column": 5 + }, + "end": { + "line": 16, + "column": 6 + } + }, + "name": "T" + } + }, + "indexType": { + "type": "TSTypeReference", + "start": 292, + "end": 293, + "loc": { + "start": { + "line": 16, + "column": 7 + }, + "end": { + "line": 16, + "column": 8 + } + }, + "typeName": { + "type": "Identifier", + "start": 292, + "end": 293, + "loc": { + "start": { + "line": 16, + "column": 7 + }, + "end": { + "line": 16, + "column": 8 + } + }, + "name": "K" + } + } + } + }, + "leadingComments": [ + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 165, + "end": 219 + } + ] + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/input.svelte b/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/input.svelte new file mode 100644 index 000000000..d9cbaafa8 --- /dev/null +++ b/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/input.svelte @@ -0,0 +1,18 @@ + diff --git a/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/output_prettier.svelte b/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/output_prettier.svelte new file mode 100644 index 000000000..eb81404b4 --- /dev/null +++ b/tests/fixtures/typescript/types/mapped_key_glued_block_comment_prettier_divergence/output_prettier.svelte @@ -0,0 +1,20 @@ + diff --git a/tests/fixtures/typescript/types/tuple/element_glued_block_comment/expected.json b/tests/fixtures/typescript/types/tuple/element_glued_block_comment/expected.json new file mode 100644 index 000000000..31c38aa13 --- /dev/null +++ b/tests/fixtures/typescript/types/tuple/element_glued_block_comment/expected.json @@ -0,0 +1,967 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 828, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " A glued pair of blocks before the first element stays glued, then breaks.", + "start": 20, + "end": 96, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 77 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 111, + "end": 119, + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 4, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 120, + "end": 128, + "loc": { + "start": { + "line": 4, + "column": 11 + }, + "end": { + "line": 4, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " A glued pair between elements stays glued.", + "start": 212, + "end": 257, + "loc": { + "start": { + "line": 8, + "column": 1 + }, + "end": { + "line": 8, + "column": 46 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 312, + "end": 320, + "loc": { + "start": { + "line": 11, + "column": 2 + }, + "end": { + "line": 11, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 321, + "end": 329, + "loc": { + "start": { + "line": 11, + "column": 11 + }, + "end": { + "line": 11, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " A glued pair sharing the gap with a line comment stays glued.", + "start": 373, + "end": 437, + "loc": { + "start": { + "line": 14, + "column": 1 + }, + "end": { + "line": 14, + "column": 65 + } + } + }, + { + "type": "Line", + "value": " line", + "start": 492, + "end": 499, + "loc": { + "start": { + "line": 17, + "column": 2 + }, + "end": { + "line": 17, + "column": 9 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 502, + "end": 510, + "loc": { + "start": { + "line": 18, + "column": 2 + }, + "end": { + "line": 18, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 511, + "end": 519, + "loc": { + "start": { + "line": 18, + "column": 11 + }, + "end": { + "line": 18, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 565, + "end": 619, + "loc": { + "start": { + "line": 22, + "column": 1 + }, + "end": { + "line": 22, + "column": 55 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 674, + "end": 682, + "loc": { + "start": { + "line": 25, + "column": 2 + }, + "end": { + "line": 25, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 685, + "end": 693, + "loc": { + "start": { + "line": 26, + "column": 2 + }, + "end": { + "line": 26, + "column": 10 + } + } + }, + { + "type": "Line", + "value": " A same-line block does not force expansion.", + "start": 739, + "end": 785, + "loc": { + "start": { + "line": 30, + "column": 1 + }, + "end": { + "line": 30, + "column": 47 + } + } + }, + { + "type": "Block", + "value": " c ", + "start": 803, + "end": 810, + "loc": { + "start": { + "line": 31, + "column": 17 + }, + "end": { + "line": 31, + "column": 24 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 827, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 818, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 32, + "column": 9 + } + }, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start": 98, + "end": 209, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 6, + "column": 3 + } + }, + "id": { + "type": "Identifier", + "start": 103, + "end": 104, + "loc": { + "start": { + "line": 3, + "column": 6 + }, + "end": { + "line": 3, + "column": 7 + } + }, + "name": "A" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start": 107, + "end": 208, + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 6, + "column": 2 + } + }, + "elementTypes": [ + { + "type": "TSTypeReference", + "start": 129, + "end": 165, + "loc": { + "start": { + "line": 4, + "column": 20 + }, + "end": { + "line": 4, + "column": 56 + } + }, + "typeName": { + "type": "Identifier", + "start": 129, + "end": 165, + "loc": { + "start": { + "line": 4, + "column": 20 + }, + "end": { + "line": 4, + "column": 56 + } + }, + "name": "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 111, + "end": 119 + }, + { + "type": "Block", + "value": " c2 ", + "start": 120, + "end": 128 + } + ] + }, + { + "type": "TSTypeReference", + "start": 169, + "end": 205, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 38 + } + }, + "typeName": { + "type": "Identifier", + "start": 169, + "end": 205, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 38 + } + }, + "name": "Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair of blocks before the first element stays glued, then breaks.", + "start": 20, + "end": 96 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 259, + "end": 370, + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 12, + "column": 3 + } + }, + "id": { + "type": "Identifier", + "start": 264, + "end": 265, + "loc": { + "start": { + "line": 9, + "column": 6 + }, + "end": { + "line": 9, + "column": 7 + } + }, + "name": "B" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start": 268, + "end": 369, + "loc": { + "start": { + "line": 9, + "column": 10 + }, + "end": { + "line": 12, + "column": 2 + } + }, + "elementTypes": [ + { + "type": "TSTypeReference", + "start": 272, + "end": 308, + "loc": { + "start": { + "line": 10, + "column": 2 + }, + "end": { + "line": 10, + "column": 38 + } + }, + "typeName": { + "type": "Identifier", + "start": 272, + "end": 308, + "loc": { + "start": { + "line": 10, + "column": 2 + }, + "end": { + "line": 10, + "column": 38 + } + }, + "name": "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + }, + { + "type": "TSTypeReference", + "start": 330, + "end": 366, + "loc": { + "start": { + "line": 11, + "column": 20 + }, + "end": { + "line": 11, + "column": 56 + } + }, + "typeName": { + "type": "Identifier", + "start": 330, + "end": 366, + "loc": { + "start": { + "line": 11, + "column": 20 + }, + "end": { + "line": 11, + "column": 56 + } + }, + "name": "Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 312, + "end": 320 + }, + { + "type": "Block", + "value": " c2 ", + "start": 321, + "end": 329 + } + ] + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair between elements stays glued.", + "start": 212, + "end": 257 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 439, + "end": 562, + "loc": { + "start": { + "line": 15, + "column": 1 + }, + "end": { + "line": 20, + "column": 3 + } + }, + "id": { + "type": "Identifier", + "start": 444, + "end": 445, + "loc": { + "start": { + "line": 15, + "column": 6 + }, + "end": { + "line": 15, + "column": 7 + } + }, + "name": "C" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start": 448, + "end": 561, + "loc": { + "start": { + "line": 15, + "column": 10 + }, + "end": { + "line": 20, + "column": 2 + } + }, + "elementTypes": [ + { + "type": "TSTypeReference", + "start": 452, + "end": 488, + "loc": { + "start": { + "line": 16, + "column": 2 + }, + "end": { + "line": 16, + "column": 38 + } + }, + "typeName": { + "type": "Identifier", + "start": 452, + "end": 488, + "loc": { + "start": { + "line": 16, + "column": 2 + }, + "end": { + "line": 16, + "column": 38 + } + }, + "name": "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + }, + { + "type": "TSTypeReference", + "start": 522, + "end": 558, + "loc": { + "start": { + "line": 19, + "column": 2 + }, + "end": { + "line": 19, + "column": 38 + } + }, + "typeName": { + "type": "Identifier", + "start": 522, + "end": 558, + "loc": { + "start": { + "line": 19, + "column": 2 + }, + "end": { + "line": 19, + "column": 38 + } + }, + "name": "Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + }, + "leadingComments": [ + { + "type": "Line", + "value": " line", + "start": 492, + "end": 499 + }, + { + "type": "Block", + "value": " c1 ", + "start": 502, + "end": 510 + }, + { + "type": "Block", + "value": " c2 ", + "start": 511, + "end": 519 + } + ] + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair sharing the gap with a line comment stays glued.", + "start": 373, + "end": 437 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 621, + "end": 736, + "loc": { + "start": { + "line": 23, + "column": 1 + }, + "end": { + "line": 28, + "column": 3 + } + }, + "id": { + "type": "Identifier", + "start": 626, + "end": 627, + "loc": { + "start": { + "line": 23, + "column": 6 + }, + "end": { + "line": 23, + "column": 7 + } + }, + "name": "D" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start": 630, + "end": 735, + "loc": { + "start": { + "line": 23, + "column": 10 + }, + "end": { + "line": 28, + "column": 2 + } + }, + "elementTypes": [ + { + "type": "TSTypeReference", + "start": 634, + "end": 670, + "loc": { + "start": { + "line": 24, + "column": 2 + }, + "end": { + "line": 24, + "column": 38 + } + }, + "typeName": { + "type": "Identifier", + "start": 634, + "end": 670, + "loc": { + "start": { + "line": 24, + "column": 2 + }, + "end": { + "line": 24, + "column": 38 + } + }, + "name": "Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + }, + { + "type": "TSTypeReference", + "start": 696, + "end": 732, + "loc": { + "start": { + "line": 27, + "column": 2 + }, + "end": { + "line": 27, + "column": 38 + } + }, + "typeName": { + "type": "Identifier", + "start": 696, + "end": 732, + "loc": { + "start": { + "line": 27, + "column": 2 + }, + "end": { + "line": 27, + "column": 38 + } + }, + "name": "Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 674, + "end": 682 + }, + { + "type": "Block", + "value": " c2 ", + "start": 685, + "end": 693 + } + ] + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 565, + "end": 619 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 787, + "end": 817, + "loc": { + "start": { + "line": 31, + "column": 1 + }, + "end": { + "line": 31, + "column": 31 + } + }, + "id": { + "type": "Identifier", + "start": 792, + "end": 793, + "loc": { + "start": { + "line": 31, + "column": 6 + }, + "end": { + "line": 31, + "column": 7 + } + }, + "name": "E" + }, + "typeAnnotation": { + "type": "TSTupleType", + "start": 796, + "end": 816, + "loc": { + "start": { + "line": 31, + "column": 10 + }, + "end": { + "line": 31, + "column": 30 + } + }, + "elementTypes": [ + { + "type": "TSTypeReference", + "start": 797, + "end": 801, + "loc": { + "start": { + "line": 31, + "column": 11 + }, + "end": { + "line": 31, + "column": 15 + } + }, + "typeName": { + "type": "Identifier", + "start": 797, + "end": 801, + "loc": { + "start": { + "line": 31, + "column": 11 + }, + "end": { + "line": 31, + "column": 15 + } + }, + "name": "Aaaa" + }, + "trailingComments": [ + { + "type": "Block", + "value": " c ", + "start": 803, + "end": 810 + } + ] + }, + { + "type": "TSTypeReference", + "start": 811, + "end": 815, + "loc": { + "start": { + "line": 31, + "column": 25 + }, + "end": { + "line": 31, + "column": 29 + } + }, + "typeName": { + "type": "Identifier", + "start": 811, + "end": 815, + "loc": { + "start": { + "line": 31, + "column": 25 + }, + "end": { + "line": 31, + "column": 29 + } + }, + "name": "Bbbb" + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A same-line block does not force expansion.", + "start": 739, + "end": 785 + } + ] + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/types/tuple/element_glued_block_comment/input.svelte b/tests/fixtures/typescript/types/tuple/element_glued_block_comment/input.svelte new file mode 100644 index 000000000..e10e72f7f --- /dev/null +++ b/tests/fixtures/typescript/types/tuple/element_glued_block_comment/input.svelte @@ -0,0 +1,32 @@ + diff --git a/tests/fixtures/typescript/types/tuple/element_glued_block_comment/unformatted_glued_run_own_line.svelte b/tests/fixtures/typescript/types/tuple/element_glued_block_comment/unformatted_glued_run_own_line.svelte new file mode 100644 index 000000000..0c7912cc4 --- /dev/null +++ b/tests/fixtures/typescript/types/tuple/element_glued_block_comment/unformatted_glued_run_own_line.svelte @@ -0,0 +1,34 @@ + diff --git a/tests/fixtures/typescript/types/type_args/arg_glued_block_comment/expected.json b/tests/fixtures/typescript/types/type_args/arg_glued_block_comment/expected.json new file mode 100644 index 000000000..b098a8c92 --- /dev/null +++ b/tests/fixtures/typescript/types/type_args/arg_glued_block_comment/expected.json @@ -0,0 +1,1216 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 1007, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " A glued pair before the first type argument of a call stays glued.", + "start": 20, + "end": 89, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 70 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 108, + "end": 116, + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 4, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 117, + "end": 125, + "loc": { + "start": { + "line": 4, + "column": 11 + }, + "end": { + "line": 4, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " A glued pair between call type arguments stays glued.", + "start": 226, + "end": 282, + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 9, + "column": 57 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 347, + "end": 355, + "loc": { + "start": { + "line": 12, + "column": 2 + }, + "end": { + "line": 12, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 356, + "end": 364, + "loc": { + "start": { + "line": 12, + "column": 11 + }, + "end": { + "line": 12, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " A glued pair in a type-position type-argument list stays glued.", + "start": 419, + "end": 485, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 67 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 503, + "end": 511, + "loc": { + "start": { + "line": 18, + "column": 2 + }, + "end": { + "line": 18, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 512, + "end": 520, + "loc": { + "start": { + "line": 18, + "column": 11 + }, + "end": { + "line": 18, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " A glued pair after a line comment stays glued.", + "start": 618, + "end": 667, + "loc": { + "start": { + "line": 23, + "column": 1 + }, + "end": { + "line": 23, + "column": 50 + } + } + }, + { + "type": "Line", + "value": " line", + "start": 731, + "end": 738, + "loc": { + "start": { + "line": 26, + "column": 2 + }, + "end": { + "line": 26, + "column": 9 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 741, + "end": 749, + "loc": { + "start": { + "line": 27, + "column": 2 + }, + "end": { + "line": 27, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 750, + "end": 758, + "loc": { + "start": { + "line": 27, + "column": 11 + }, + "end": { + "line": 27, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 810, + "end": 864, + "loc": { + "start": { + "line": 31, + "column": 1 + }, + "end": { + "line": 31, + "column": 55 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 928, + "end": 936, + "loc": { + "start": { + "line": 34, + "column": 2 + }, + "end": { + "line": 34, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 939, + "end": 947, + "loc": { + "start": { + "line": 35, + "column": 2 + }, + "end": { + "line": 35, + "column": 10 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 1006, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 997, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 38, + "column": 9 + } + }, + "body": [ + { + "type": "VariableDeclaration", + "start": 91, + "end": 223, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 7, + "column": 6 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 97, + "end": 222, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 7, + "column": 5 + } + }, + "id": { + "type": "Identifier", + "start": 97, + "end": 98, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 3, + "column": 8 + } + }, + "name": "a" + }, + "init": { + "type": "CallExpression", + "start": 101, + "end": 222, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 7, + "column": 5 + } + }, + "callee": { + "type": "Identifier", + "start": 101, + "end": 104, + "loc": { + "start": { + "line": 3, + "column": 11 + }, + "end": { + "line": 3, + "column": 14 + } + }, + "name": "fn1" + }, + "arguments": [ + { + "type": "Identifier", + "start": 220, + "end": 221, + "loc": { + "start": { + "line": 7, + "column": 3 + }, + "end": { + "line": 7, + "column": 4 + } + }, + "name": "x", + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 108, + "end": 116 + }, + { + "type": "Block", + "value": " c2 ", + "start": 117, + "end": 125 + } + ] + } + ], + "typeArguments": { + "type": "TSTypeParameterInstantiation", + "start": 104, + "end": 219, + "loc": { + "start": { + "line": 3, + "column": 14 + }, + "end": { + "line": 7, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeReference", + "start": 128, + "end": 170, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 128, + "end": 170, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 44 + } + }, + "name": "AaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLong" + } + }, + { + "type": "TSTypeReference", + "start": 174, + "end": 216, + "loc": { + "start": { + "line": 6, + "column": 2 + }, + "end": { + "line": 6, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 174, + "end": 216, + "loc": { + "start": { + "line": 6, + "column": 2 + }, + "end": { + "line": 6, + "column": 44 + } + }, + "name": "BbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLong" + } + } + ] + } + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair before the first type argument of a call stays glued.", + "start": 20, + "end": 89 + } + ] + }, + { + "type": "VariableDeclaration", + "start": 284, + "end": 416, + "loc": { + "start": { + "line": 10, + "column": 1 + }, + "end": { + "line": 14, + "column": 6 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 290, + "end": 415, + "loc": { + "start": { + "line": 10, + "column": 7 + }, + "end": { + "line": 14, + "column": 5 + } + }, + "id": { + "type": "Identifier", + "start": 290, + "end": 291, + "loc": { + "start": { + "line": 10, + "column": 7 + }, + "end": { + "line": 10, + "column": 8 + } + }, + "name": "b" + }, + "init": { + "type": "CallExpression", + "start": 294, + "end": 415, + "loc": { + "start": { + "line": 10, + "column": 11 + }, + "end": { + "line": 14, + "column": 5 + } + }, + "callee": { + "type": "Identifier", + "start": 294, + "end": 297, + "loc": { + "start": { + "line": 10, + "column": 11 + }, + "end": { + "line": 10, + "column": 14 + } + }, + "name": "fn2" + }, + "arguments": [ + { + "type": "Identifier", + "start": 413, + "end": 414, + "loc": { + "start": { + "line": 14, + "column": 3 + }, + "end": { + "line": 14, + "column": 4 + } + }, + "name": "x", + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 347, + "end": 355 + }, + { + "type": "Block", + "value": " c2 ", + "start": 356, + "end": 364 + } + ] + } + ], + "typeArguments": { + "type": "TSTypeParameterInstantiation", + "start": 297, + "end": 412, + "loc": { + "start": { + "line": 10, + "column": 14 + }, + "end": { + "line": 14, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeReference", + "start": 301, + "end": 343, + "loc": { + "start": { + "line": 11, + "column": 2 + }, + "end": { + "line": 11, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 301, + "end": 343, + "loc": { + "start": { + "line": 11, + "column": 2 + }, + "end": { + "line": 11, + "column": 44 + } + }, + "name": "AaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLong" + } + }, + { + "type": "TSTypeReference", + "start": 367, + "end": 409, + "loc": { + "start": { + "line": 13, + "column": 2 + }, + "end": { + "line": 13, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 367, + "end": 409, + "loc": { + "start": { + "line": 13, + "column": 2 + }, + "end": { + "line": 13, + "column": 44 + } + }, + "name": "BbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLong" + } + } + ] + } + } + } + ], + "kind": "const", + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair between call type arguments stays glued.", + "start": 226, + "end": 282 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 487, + "end": 615, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 21, + "column": 3 + } + }, + "id": { + "type": "Identifier", + "start": 492, + "end": 493, + "loc": { + "start": { + "line": 17, + "column": 6 + }, + "end": { + "line": 17, + "column": 7 + } + }, + "name": "A" + }, + "typeAnnotation": { + "type": "TSTypeReference", + "start": 496, + "end": 614, + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 21, + "column": 2 + } + }, + "typeName": { + "type": "Identifier", + "start": 496, + "end": 499, + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 13 + } + }, + "name": "Foo" + }, + "typeArguments": { + "type": "TSTypeParameterInstantiation", + "start": 499, + "end": 614, + "loc": { + "start": { + "line": 17, + "column": 13 + }, + "end": { + "line": 21, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeReference", + "start": 523, + "end": 565, + "loc": { + "start": { + "line": 19, + "column": 2 + }, + "end": { + "line": 19, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 523, + "end": 565, + "loc": { + "start": { + "line": 19, + "column": 2 + }, + "end": { + "line": 19, + "column": 44 + } + }, + "name": "AaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLong" + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 503, + "end": 511 + }, + { + "type": "Block", + "value": " c2 ", + "start": 512, + "end": 520 + } + ] + }, + { + "type": "TSTypeReference", + "start": 569, + "end": 611, + "loc": { + "start": { + "line": 20, + "column": 2 + }, + "end": { + "line": 20, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 569, + "end": 611, + "loc": { + "start": { + "line": 20, + "column": 2 + }, + "end": { + "line": 20, + "column": 44 + } + }, + "name": "BbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLong" + } + } + ] + } + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair in a type-position type-argument list stays glued.", + "start": 419, + "end": 485 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 669, + "end": 807, + "loc": { + "start": { + "line": 24, + "column": 1 + }, + "end": { + "line": 29, + "column": 3 + } + }, + "id": { + "type": "Identifier", + "start": 674, + "end": 675, + "loc": { + "start": { + "line": 24, + "column": 6 + }, + "end": { + "line": 24, + "column": 7 + } + }, + "name": "B" + }, + "typeAnnotation": { + "type": "TSTypeReference", + "start": 678, + "end": 806, + "loc": { + "start": { + "line": 24, + "column": 10 + }, + "end": { + "line": 29, + "column": 2 + } + }, + "typeName": { + "type": "Identifier", + "start": 678, + "end": 681, + "loc": { + "start": { + "line": 24, + "column": 10 + }, + "end": { + "line": 24, + "column": 13 + } + }, + "name": "Foo" + }, + "typeArguments": { + "type": "TSTypeParameterInstantiation", + "start": 681, + "end": 806, + "loc": { + "start": { + "line": 24, + "column": 13 + }, + "end": { + "line": 29, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeReference", + "start": 685, + "end": 727, + "loc": { + "start": { + "line": 25, + "column": 2 + }, + "end": { + "line": 25, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 685, + "end": 727, + "loc": { + "start": { + "line": 25, + "column": 2 + }, + "end": { + "line": 25, + "column": 44 + } + }, + "name": "AaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLong" + } + }, + { + "type": "TSTypeReference", + "start": 761, + "end": 803, + "loc": { + "start": { + "line": 28, + "column": 2 + }, + "end": { + "line": 28, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 761, + "end": 803, + "loc": { + "start": { + "line": 28, + "column": 2 + }, + "end": { + "line": 28, + "column": 44 + } + }, + "name": "BbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLong" + }, + "leadingComments": [ + { + "type": "Line", + "value": " line", + "start": 731, + "end": 738 + }, + { + "type": "Block", + "value": " c1 ", + "start": 741, + "end": 749 + }, + { + "type": "Block", + "value": " c2 ", + "start": 750, + "end": 758 + } + ] + } + ] + } + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair after a line comment stays glued.", + "start": 618, + "end": 667 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 866, + "end": 996, + "loc": { + "start": { + "line": 32, + "column": 1 + }, + "end": { + "line": 37, + "column": 3 + } + }, + "id": { + "type": "Identifier", + "start": 871, + "end": 872, + "loc": { + "start": { + "line": 32, + "column": 6 + }, + "end": { + "line": 32, + "column": 7 + } + }, + "name": "C" + }, + "typeAnnotation": { + "type": "TSTypeReference", + "start": 875, + "end": 995, + "loc": { + "start": { + "line": 32, + "column": 10 + }, + "end": { + "line": 37, + "column": 2 + } + }, + "typeName": { + "type": "Identifier", + "start": 875, + "end": 878, + "loc": { + "start": { + "line": 32, + "column": 10 + }, + "end": { + "line": 32, + "column": 13 + } + }, + "name": "Foo" + }, + "typeArguments": { + "type": "TSTypeParameterInstantiation", + "start": 878, + "end": 995, + "loc": { + "start": { + "line": 32, + "column": 13 + }, + "end": { + "line": 37, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeReference", + "start": 882, + "end": 924, + "loc": { + "start": { + "line": 33, + "column": 2 + }, + "end": { + "line": 33, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 882, + "end": 924, + "loc": { + "start": { + "line": 33, + "column": 2 + }, + "end": { + "line": 33, + "column": 44 + } + }, + "name": "AaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaLong" + } + }, + { + "type": "TSTypeReference", + "start": 950, + "end": 992, + "loc": { + "start": { + "line": 36, + "column": 2 + }, + "end": { + "line": 36, + "column": 44 + } + }, + "typeName": { + "type": "Identifier", + "start": 950, + "end": 992, + "loc": { + "start": { + "line": 36, + "column": 2 + }, + "end": { + "line": 36, + "column": 44 + } + }, + "name": "BbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLong" + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 928, + "end": 936 + }, + { + "type": "Block", + "value": " c2 ", + "start": 939, + "end": 947 + } + ] + } + ] + } + }, + "leadingComments": [ + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 810, + "end": 864 + } + ] + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/types/type_args/arg_glued_block_comment/input.svelte b/tests/fixtures/typescript/types/type_args/arg_glued_block_comment/input.svelte new file mode 100644 index 000000000..fcc061160 --- /dev/null +++ b/tests/fixtures/typescript/types/type_args/arg_glued_block_comment/input.svelte @@ -0,0 +1,38 @@ + diff --git a/tests/fixtures/typescript/types/type_params/param_glued_block_comment/expected.json b/tests/fixtures/typescript/types/type_params/param_glued_block_comment/expected.json new file mode 100644 index 000000000..1f2912114 --- /dev/null +++ b/tests/fixtures/typescript/types/type_params/param_glued_block_comment/expected.json @@ -0,0 +1,1714 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 1359, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " A glued pair before the first type param stays glued; the param breaks below.", + "start": 20, + "end": 100, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 81 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 118, + "end": 126, + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 4, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 127, + "end": 135, + "loc": { + "start": { + "line": 4, + "column": 11 + }, + "end": { + "line": 4, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " A glued pair between params stays glued.", + "start": 274, + "end": 317, + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 9, + "column": 44 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 386, + "end": 394, + "loc": { + "start": { + "line": 12, + "column": 2 + }, + "end": { + "line": 12, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 395, + "end": 403, + "loc": { + "start": { + "line": 12, + "column": 11 + }, + "end": { + "line": 12, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " A glued pair after a line comment stays glued.", + "start": 491, + "end": 540, + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 16, + "column": 50 + } + } + }, + { + "type": "Line", + "value": " line", + "start": 609, + "end": 616, + "loc": { + "start": { + "line": 19, + "column": 2 + }, + "end": { + "line": 19, + "column": 9 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 619, + "end": 627, + "loc": { + "start": { + "line": 20, + "column": 2 + }, + "end": { + "line": 20, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 628, + "end": 636, + "loc": { + "start": { + "line": 20, + "column": 11 + }, + "end": { + "line": 20, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 724, + "end": 778, + "loc": { + "start": { + "line": 24, + "column": 1 + }, + "end": { + "line": 24, + "column": 55 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 847, + "end": 855, + "loc": { + "start": { + "line": 27, + "column": 2 + }, + "end": { + "line": 27, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 858, + "end": 866, + "loc": { + "start": { + "line": 28, + "column": 2 + }, + "end": { + "line": 28, + "column": 10 + } + } + }, + { + "type": "Line", + "value": " A class type-param declaration takes the wrapping router.", + "start": 954, + "end": 1014, + "loc": { + "start": { + "line": 32, + "column": 1 + }, + "end": { + "line": 32, + "column": 61 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 1032, + "end": 1040, + "loc": { + "start": { + "line": 34, + "column": 2 + }, + "end": { + "line": 34, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 1041, + "end": 1049, + "loc": { + "start": { + "line": 34, + "column": 11 + }, + "end": { + "line": 34, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " An interface type-param declaration.", + "start": 1160, + "end": 1199, + "loc": { + "start": { + "line": 39, + "column": 1 + }, + "end": { + "line": 39, + "column": 40 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 1223, + "end": 1231, + "loc": { + "start": { + "line": 41, + "column": 2 + }, + "end": { + "line": 41, + "column": 10 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 1232, + "end": 1240, + "loc": { + "start": { + "line": 41, + "column": 11 + }, + "end": { + "line": 41, + "column": 19 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 1358, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 1349, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 45, + "column": 9 + } + }, + "body": [ + { + "type": "FunctionDeclaration", + "start": 102, + "end": 271, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 7, + "column": 33 + } + }, + "id": { + "type": "Identifier", + "start": 111, + "end": 114, + "loc": { + "start": { + "line": 3, + "column": 10 + }, + "end": { + "line": 3, + "column": 13 + } + }, + "name": "fn1" + }, + "expression": false, + "generator": false, + "async": false, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "start": 114, + "end": 240, + "loc": { + "start": { + "line": 3, + "column": 13 + }, + "end": { + "line": 7, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "start": 138, + "end": 185, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 49 + } + }, + "name": "TFirstLongTypeParameter", + "constraint": { + "type": "TSStringKeyword", + "start": 170, + "end": 176, + "loc": { + "start": { + "line": 5, + "column": 34 + }, + "end": { + "line": 5, + "column": 40 + } + } + }, + "default": { + "type": "TSStringKeyword", + "start": 179, + "end": 185, + "loc": { + "start": { + "line": 5, + "column": 43 + }, + "end": { + "line": 5, + "column": 49 + } + } + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 118, + "end": 126 + }, + { + "type": "Block", + "value": " c2 ", + "start": 127, + "end": 135 + } + ] + }, + { + "type": "TSTypeParameter", + "start": 189, + "end": 237, + "loc": { + "start": { + "line": 6, + "column": 2 + }, + "end": { + "line": 6, + "column": 50 + } + }, + "name": "TSecondLongTypeParameter", + "constraint": { + "type": "TSNumberKeyword", + "start": 222, + "end": 228, + "loc": { + "start": { + "line": 6, + "column": 35 + }, + "end": { + "line": 6, + "column": 41 + } + } + }, + "default": { + "type": "TSNumberKeyword", + "start": 231, + "end": 237, + "loc": { + "start": { + "line": 6, + "column": 44 + }, + "end": { + "line": 6, + "column": 50 + } + } + } + } + ] + }, + "params": [ + { + "type": "Identifier", + "start": 241, + "end": 267, + "loc": { + "start": { + "line": 7, + "column": 3 + }, + "end": { + "line": 7, + "column": 29 + } + }, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 242, + "end": 267, + "loc": { + "start": { + "line": 7, + "column": 4 + }, + "end": { + "line": 7, + "column": 29 + } + }, + "typeAnnotation": { + "type": "TSTypeReference", + "start": 244, + "end": 267, + "loc": { + "start": { + "line": 7, + "column": 6 + }, + "end": { + "line": 7, + "column": 29 + } + }, + "typeName": { + "type": "Identifier", + "start": 244, + "end": 267, + "loc": { + "start": { + "line": 7, + "column": 6 + }, + "end": { + "line": 7, + "column": 29 + } + }, + "name": "TFirstLongTypeParameter" + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "start": 269, + "end": 271, + "loc": { + "start": { + "line": 7, + "column": 31 + }, + "end": { + "line": 7, + "column": 33 + } + }, + "body": [] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair before the first type param stays glued; the param breaks below.", + "start": 20, + "end": 100 + } + ] + }, + { + "type": "FunctionDeclaration", + "start": 319, + "end": 488, + "loc": { + "start": { + "line": 10, + "column": 1 + }, + "end": { + "line": 14, + "column": 33 + } + }, + "id": { + "type": "Identifier", + "start": 328, + "end": 331, + "loc": { + "start": { + "line": 10, + "column": 10 + }, + "end": { + "line": 10, + "column": 13 + } + }, + "name": "fn2" + }, + "expression": false, + "generator": false, + "async": false, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "start": 331, + "end": 457, + "loc": { + "start": { + "line": 10, + "column": 13 + }, + "end": { + "line": 14, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "start": 335, + "end": 382, + "loc": { + "start": { + "line": 11, + "column": 2 + }, + "end": { + "line": 11, + "column": 49 + } + }, + "name": "TFirstLongTypeParameter", + "constraint": { + "type": "TSStringKeyword", + "start": 367, + "end": 373, + "loc": { + "start": { + "line": 11, + "column": 34 + }, + "end": { + "line": 11, + "column": 40 + } + } + }, + "default": { + "type": "TSStringKeyword", + "start": 376, + "end": 382, + "loc": { + "start": { + "line": 11, + "column": 43 + }, + "end": { + "line": 11, + "column": 49 + } + } + } + }, + { + "type": "TSTypeParameter", + "start": 406, + "end": 454, + "loc": { + "start": { + "line": 13, + "column": 2 + }, + "end": { + "line": 13, + "column": 50 + } + }, + "name": "TSecondLongTypeParameter", + "constraint": { + "type": "TSNumberKeyword", + "start": 439, + "end": 445, + "loc": { + "start": { + "line": 13, + "column": 35 + }, + "end": { + "line": 13, + "column": 41 + } + } + }, + "default": { + "type": "TSNumberKeyword", + "start": 448, + "end": 454, + "loc": { + "start": { + "line": 13, + "column": 44 + }, + "end": { + "line": 13, + "column": 50 + } + } + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 386, + "end": 394 + }, + { + "type": "Block", + "value": " c2 ", + "start": 395, + "end": 403 + } + ] + } + ] + }, + "params": [ + { + "type": "Identifier", + "start": 458, + "end": 484, + "loc": { + "start": { + "line": 14, + "column": 3 + }, + "end": { + "line": 14, + "column": 29 + } + }, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 459, + "end": 484, + "loc": { + "start": { + "line": 14, + "column": 4 + }, + "end": { + "line": 14, + "column": 29 + } + }, + "typeAnnotation": { + "type": "TSTypeReference", + "start": 461, + "end": 484, + "loc": { + "start": { + "line": 14, + "column": 6 + }, + "end": { + "line": 14, + "column": 29 + } + }, + "typeName": { + "type": "Identifier", + "start": 461, + "end": 484, + "loc": { + "start": { + "line": 14, + "column": 6 + }, + "end": { + "line": 14, + "column": 29 + } + }, + "name": "TFirstLongTypeParameter" + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "start": 486, + "end": 488, + "loc": { + "start": { + "line": 14, + "column": 31 + }, + "end": { + "line": 14, + "column": 33 + } + }, + "body": [] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair between params stays glued.", + "start": 274, + "end": 317 + } + ] + }, + { + "type": "FunctionDeclaration", + "start": 542, + "end": 721, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 22, + "column": 33 + } + }, + "id": { + "type": "Identifier", + "start": 551, + "end": 554, + "loc": { + "start": { + "line": 17, + "column": 10 + }, + "end": { + "line": 17, + "column": 13 + } + }, + "name": "fn3" + }, + "expression": false, + "generator": false, + "async": false, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "start": 554, + "end": 690, + "loc": { + "start": { + "line": 17, + "column": 13 + }, + "end": { + "line": 22, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "start": 558, + "end": 605, + "loc": { + "start": { + "line": 18, + "column": 2 + }, + "end": { + "line": 18, + "column": 49 + } + }, + "name": "TFirstLongTypeParameter", + "constraint": { + "type": "TSStringKeyword", + "start": 590, + "end": 596, + "loc": { + "start": { + "line": 18, + "column": 34 + }, + "end": { + "line": 18, + "column": 40 + } + } + }, + "default": { + "type": "TSStringKeyword", + "start": 599, + "end": 605, + "loc": { + "start": { + "line": 18, + "column": 43 + }, + "end": { + "line": 18, + "column": 49 + } + } + } + }, + { + "type": "TSTypeParameter", + "start": 639, + "end": 687, + "loc": { + "start": { + "line": 21, + "column": 2 + }, + "end": { + "line": 21, + "column": 50 + } + }, + "name": "TSecondLongTypeParameter", + "constraint": { + "type": "TSNumberKeyword", + "start": 672, + "end": 678, + "loc": { + "start": { + "line": 21, + "column": 35 + }, + "end": { + "line": 21, + "column": 41 + } + } + }, + "default": { + "type": "TSNumberKeyword", + "start": 681, + "end": 687, + "loc": { + "start": { + "line": 21, + "column": 44 + }, + "end": { + "line": 21, + "column": 50 + } + } + }, + "leadingComments": [ + { + "type": "Line", + "value": " line", + "start": 609, + "end": 616 + }, + { + "type": "Block", + "value": " c1 ", + "start": 619, + "end": 627 + }, + { + "type": "Block", + "value": " c2 ", + "start": 628, + "end": 636 + } + ] + } + ] + }, + "params": [ + { + "type": "Identifier", + "start": 691, + "end": 717, + "loc": { + "start": { + "line": 22, + "column": 3 + }, + "end": { + "line": 22, + "column": 29 + } + }, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 692, + "end": 717, + "loc": { + "start": { + "line": 22, + "column": 4 + }, + "end": { + "line": 22, + "column": 29 + } + }, + "typeAnnotation": { + "type": "TSTypeReference", + "start": 694, + "end": 717, + "loc": { + "start": { + "line": 22, + "column": 6 + }, + "end": { + "line": 22, + "column": 29 + } + }, + "typeName": { + "type": "Identifier", + "start": 694, + "end": 717, + "loc": { + "start": { + "line": 22, + "column": 6 + }, + "end": { + "line": 22, + "column": 29 + } + }, + "name": "TFirstLongTypeParameter" + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "start": 719, + "end": 721, + "loc": { + "start": { + "line": 22, + "column": 31 + }, + "end": { + "line": 22, + "column": 33 + } + }, + "body": [] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair after a line comment stays glued.", + "start": 491, + "end": 540 + } + ] + }, + { + "type": "FunctionDeclaration", + "start": 780, + "end": 951, + "loc": { + "start": { + "line": 25, + "column": 1 + }, + "end": { + "line": 30, + "column": 33 + } + }, + "id": { + "type": "Identifier", + "start": 789, + "end": 792, + "loc": { + "start": { + "line": 25, + "column": 10 + }, + "end": { + "line": 25, + "column": 13 + } + }, + "name": "fn4" + }, + "expression": false, + "generator": false, + "async": false, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "start": 792, + "end": 920, + "loc": { + "start": { + "line": 25, + "column": 13 + }, + "end": { + "line": 30, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "start": 796, + "end": 843, + "loc": { + "start": { + "line": 26, + "column": 2 + }, + "end": { + "line": 26, + "column": 49 + } + }, + "name": "TFirstLongTypeParameter", + "constraint": { + "type": "TSStringKeyword", + "start": 828, + "end": 834, + "loc": { + "start": { + "line": 26, + "column": 34 + }, + "end": { + "line": 26, + "column": 40 + } + } + }, + "default": { + "type": "TSStringKeyword", + "start": 837, + "end": 843, + "loc": { + "start": { + "line": 26, + "column": 43 + }, + "end": { + "line": 26, + "column": 49 + } + } + } + }, + { + "type": "TSTypeParameter", + "start": 869, + "end": 917, + "loc": { + "start": { + "line": 29, + "column": 2 + }, + "end": { + "line": 29, + "column": 50 + } + }, + "name": "TSecondLongTypeParameter", + "constraint": { + "type": "TSNumberKeyword", + "start": 902, + "end": 908, + "loc": { + "start": { + "line": 29, + "column": 35 + }, + "end": { + "line": 29, + "column": 41 + } + } + }, + "default": { + "type": "TSNumberKeyword", + "start": 911, + "end": 917, + "loc": { + "start": { + "line": 29, + "column": 44 + }, + "end": { + "line": 29, + "column": 50 + } + } + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 847, + "end": 855 + }, + { + "type": "Block", + "value": " c2 ", + "start": 858, + "end": 866 + } + ] + } + ] + }, + "params": [ + { + "type": "Identifier", + "start": 921, + "end": 947, + "loc": { + "start": { + "line": 30, + "column": 3 + }, + "end": { + "line": 30, + "column": 29 + } + }, + "name": "x", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 922, + "end": 947, + "loc": { + "start": { + "line": 30, + "column": 4 + }, + "end": { + "line": 30, + "column": 29 + } + }, + "typeAnnotation": { + "type": "TSTypeReference", + "start": 924, + "end": 947, + "loc": { + "start": { + "line": 30, + "column": 6 + }, + "end": { + "line": 30, + "column": 29 + } + }, + "typeName": { + "type": "Identifier", + "start": 924, + "end": 947, + "loc": { + "start": { + "line": 30, + "column": 6 + }, + "end": { + "line": 30, + "column": 29 + } + }, + "name": "TFirstLongTypeParameter" + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "start": 949, + "end": 951, + "loc": { + "start": { + "line": 30, + "column": 31 + }, + "end": { + "line": 30, + "column": 33 + } + }, + "body": [] + }, + "leadingComments": [ + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 724, + "end": 778 + } + ] + }, + { + "type": "ClassDeclaration", + "start": 1016, + "end": 1157, + "loc": { + "start": { + "line": 33, + "column": 1 + }, + "end": { + "line": 37, + "column": 5 + } + }, + "id": { + "type": "Identifier", + "start": 1022, + "end": 1028, + "loc": { + "start": { + "line": 33, + "column": 7 + }, + "end": { + "line": 33, + "column": 13 + } + }, + "name": "Single" + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "start": 1028, + "end": 1154, + "loc": { + "start": { + "line": 33, + "column": 13 + }, + "end": { + "line": 37, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "start": 1052, + "end": 1099, + "loc": { + "start": { + "line": 35, + "column": 2 + }, + "end": { + "line": 35, + "column": 49 + } + }, + "name": "TFirstLongTypeParameter", + "constraint": { + "type": "TSStringKeyword", + "start": 1084, + "end": 1090, + "loc": { + "start": { + "line": 35, + "column": 34 + }, + "end": { + "line": 35, + "column": 40 + } + } + }, + "default": { + "type": "TSStringKeyword", + "start": 1093, + "end": 1099, + "loc": { + "start": { + "line": 35, + "column": 43 + }, + "end": { + "line": 35, + "column": 49 + } + } + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 1032, + "end": 1040 + }, + { + "type": "Block", + "value": " c2 ", + "start": 1041, + "end": 1049 + } + ] + }, + { + "type": "TSTypeParameter", + "start": 1103, + "end": 1151, + "loc": { + "start": { + "line": 36, + "column": 2 + }, + "end": { + "line": 36, + "column": 50 + } + }, + "name": "TSecondLongTypeParameter", + "constraint": { + "type": "TSNumberKeyword", + "start": 1136, + "end": 1142, + "loc": { + "start": { + "line": 36, + "column": 35 + }, + "end": { + "line": 36, + "column": 41 + } + } + }, + "default": { + "type": "TSNumberKeyword", + "start": 1145, + "end": 1151, + "loc": { + "start": { + "line": 36, + "column": 44 + }, + "end": { + "line": 36, + "column": 50 + } + } + } + } + ] + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 1155, + "end": 1157, + "loc": { + "start": { + "line": 37, + "column": 3 + }, + "end": { + "line": 37, + "column": 5 + } + }, + "body": [] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A class type-param declaration takes the wrapping router.", + "start": 954, + "end": 1014 + } + ] + }, + { + "type": "TSInterfaceDeclaration", + "start": 1201, + "end": 1348, + "loc": { + "start": { + "line": 40, + "column": 1 + }, + "end": { + "line": 44, + "column": 5 + } + }, + "id": { + "type": "Identifier", + "start": 1211, + "end": 1219, + "loc": { + "start": { + "line": 40, + "column": 11 + }, + "end": { + "line": 40, + "column": 19 + } + }, + "name": "Multiple" + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "start": 1219, + "end": 1345, + "loc": { + "start": { + "line": 40, + "column": 19 + }, + "end": { + "line": 44, + "column": 2 + } + }, + "params": [ + { + "type": "TSTypeParameter", + "start": 1243, + "end": 1290, + "loc": { + "start": { + "line": 42, + "column": 2 + }, + "end": { + "line": 42, + "column": 49 + } + }, + "name": "TFirstLongTypeParameter", + "constraint": { + "type": "TSStringKeyword", + "start": 1275, + "end": 1281, + "loc": { + "start": { + "line": 42, + "column": 34 + }, + "end": { + "line": 42, + "column": 40 + } + } + }, + "default": { + "type": "TSStringKeyword", + "start": 1284, + "end": 1290, + "loc": { + "start": { + "line": 42, + "column": 43 + }, + "end": { + "line": 42, + "column": 49 + } + } + }, + "leadingComments": [ + { + "type": "Block", + "value": " c1 ", + "start": 1223, + "end": 1231 + }, + { + "type": "Block", + "value": " c2 ", + "start": 1232, + "end": 1240 + } + ] + }, + { + "type": "TSTypeParameter", + "start": 1294, + "end": 1342, + "loc": { + "start": { + "line": 43, + "column": 2 + }, + "end": { + "line": 43, + "column": 50 + } + }, + "name": "TSecondLongTypeParameter", + "constraint": { + "type": "TSNumberKeyword", + "start": 1327, + "end": 1333, + "loc": { + "start": { + "line": 43, + "column": 35 + }, + "end": { + "line": 43, + "column": 41 + } + } + }, + "default": { + "type": "TSNumberKeyword", + "start": 1336, + "end": 1342, + "loc": { + "start": { + "line": 43, + "column": 44 + }, + "end": { + "line": 43, + "column": 50 + } + } + } + } + ] + }, + "body": { + "type": "TSInterfaceBody", + "start": 1346, + "end": 1348, + "loc": { + "start": { + "line": 44, + "column": 3 + }, + "end": { + "line": 44, + "column": 5 + } + }, + "body": [] + }, + "leadingComments": [ + { + "type": "Line", + "value": " An interface type-param declaration.", + "start": 1160, + "end": 1199 + } + ] + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/types/type_params/param_glued_block_comment/input.svelte b/tests/fixtures/typescript/types/type_params/param_glued_block_comment/input.svelte new file mode 100644 index 000000000..c16e80a8b --- /dev/null +++ b/tests/fixtures/typescript/types/type_params/param_glued_block_comment/input.svelte @@ -0,0 +1,45 @@ + diff --git a/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/README.md b/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/README.md new file mode 100644 index 000000000..cfbe2b6c5 --- /dev/null +++ b/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/README.md @@ -0,0 +1,23 @@ +# union_first_member_glued_block_comment_prettier_divergence + +A run of block comments leading a union's **first** member, after the leading `|` (a line +comment in that gap is what forces the multiline leading-pipe form). + +The **run itself matches prettier**: a pair the author glued stays glued and the member breaks +below (`A`), and blocks the author put on their own lines keep them (`B`). That is prettier's +`printLeadingComment` — the separator after each comment is read from the source around *that* +comment, never from where the member starts — applied through tsv's one shared +leading-comment emitter. + +## The divergence + +Only the **encoding of the offset**. Both formatters offset the run and the member past the +`|` by prettier's per-member `align(2, …)` (`union-type.js`); prettier emits that 2-column +offset as `tab + 2 spaces` under `--use-tabs`, tsv rounds it up to one whole tab. At +`tabWidth = 2` the two are the same visual width. Not specific to a comment run — any union +member with a leading line comment shows it, as case A of +[union_intersection_parens_leading_line_comment](../union_intersection_parens_leading_line_comment_prettier_divergence/) +pins. + +See [conformance_prettier.md §Tabs-Only Alignment](../../../../../docs/conformance_prettier.md#tabs-only-alignment) +and the [Tabs-Only Indentation Philosophy](../../../../../docs/conformance_prettier.md#tabs-only-indentation-philosophy). diff --git a/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/expected.json b/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/expected.json new file mode 100644 index 000000000..336be51ab --- /dev/null +++ b/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/expected.json @@ -0,0 +1,471 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 284, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " A glued pair of blocks leading the first union member stays glued.", + "start": 20, + "end": 89, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 70 + } + } + }, + { + "type": "Line", + "value": " force", + "start": 104, + "end": 112, + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 12 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 116, + "end": 124, + "loc": { + "start": { + "line": 5, + "column": 3 + }, + "end": { + "line": 5, + "column": 11 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 125, + "end": 133, + "loc": { + "start": { + "line": 5, + "column": 12 + }, + "end": { + "line": 5, + "column": 20 + } + } + }, + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 154, + "end": 208, + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 9, + "column": 55 + } + } + }, + { + "type": "Line", + "value": " force", + "start": 223, + "end": 231, + "loc": { + "start": { + "line": 11, + "column": 4 + }, + "end": { + "line": 11, + "column": 12 + } + } + }, + { + "type": "Block", + "value": " c1 ", + "start": 235, + "end": 243, + "loc": { + "start": { + "line": 12, + "column": 3 + }, + "end": { + "line": 12, + "column": 11 + } + } + }, + { + "type": "Block", + "value": " c2 ", + "start": 247, + "end": 255, + "loc": { + "start": { + "line": 13, + "column": 3 + }, + "end": { + "line": 13, + "column": 11 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 283, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 274, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 16, + "column": 9 + } + }, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start": 91, + "end": 151, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 7, + "column": 9 + } + }, + "id": { + "type": "Identifier", + "start": 96, + "end": 97, + "loc": { + "start": { + "line": 3, + "column": 6 + }, + "end": { + "line": 3, + "column": 7 + } + }, + "name": "A" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 102, + "end": 150, + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 7, + "column": 8 + } + }, + "types": [ + { + "type": "TSTypeReference", + "start": 137, + "end": 141, + "loc": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 7 + } + }, + "typeName": { + "type": "Identifier", + "start": 137, + "end": 141, + "loc": { + "start": { + "line": 6, + "column": 3 + }, + "end": { + "line": 6, + "column": 7 + } + }, + "name": "Aaaa" + }, + "leadingComments": [ + { + "type": "Line", + "value": " force", + "start": 104, + "end": 112 + }, + { + "type": "Block", + "value": " c1 ", + "start": 116, + "end": 124 + }, + { + "type": "Block", + "value": " c2 ", + "start": 125, + "end": 133 + } + ] + }, + { + "type": "TSTypeReference", + "start": 146, + "end": 150, + "loc": { + "start": { + "line": 7, + "column": 4 + }, + "end": { + "line": 7, + "column": 8 + } + }, + "typeName": { + "type": "Identifier", + "start": 146, + "end": 150, + "loc": { + "start": { + "line": 7, + "column": 4 + }, + "end": { + "line": 7, + "column": 8 + } + }, + "name": "Bbbb" + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A glued pair of blocks leading the first union member stays glued.", + "start": 20, + "end": 89 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 210, + "end": 273, + "loc": { + "start": { + "line": 10, + "column": 1 + }, + "end": { + "line": 15, + "column": 9 + } + }, + "id": { + "type": "Identifier", + "start": 215, + "end": 216, + "loc": { + "start": { + "line": 10, + "column": 6 + }, + "end": { + "line": 10, + "column": 7 + } + }, + "name": "B" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 221, + "end": 272, + "loc": { + "start": { + "line": 11, + "column": 2 + }, + "end": { + "line": 15, + "column": 8 + } + }, + "types": [ + { + "type": "TSTypeReference", + "start": 259, + "end": 263, + "loc": { + "start": { + "line": 14, + "column": 3 + }, + "end": { + "line": 14, + "column": 7 + } + }, + "typeName": { + "type": "Identifier", + "start": 259, + "end": 263, + "loc": { + "start": { + "line": 14, + "column": 3 + }, + "end": { + "line": 14, + "column": 7 + } + }, + "name": "Aaaa" + }, + "leadingComments": [ + { + "type": "Line", + "value": " force", + "start": 223, + "end": 231 + }, + { + "type": "Block", + "value": " c1 ", + "start": 235, + "end": 243 + }, + { + "type": "Block", + "value": " c2 ", + "start": 247, + "end": 255 + } + ] + }, + { + "type": "TSTypeReference", + "start": 268, + "end": 272, + "loc": { + "start": { + "line": 15, + "column": 4 + }, + "end": { + "line": 15, + "column": 8 + } + }, + "typeName": { + "type": "Identifier", + "start": 268, + "end": 272, + "loc": { + "start": { + "line": 15, + "column": 4 + }, + "end": { + "line": 15, + "column": 8 + } + }, + "name": "Bbbb" + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " Blocks the author put on their own lines keep them.", + "start": 154, + "end": 208 + } + ] + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/input.svelte b/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/input.svelte new file mode 100644 index 000000000..f1fa5097c --- /dev/null +++ b/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/input.svelte @@ -0,0 +1,16 @@ + diff --git a/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/output_prettier.svelte b/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/output_prettier.svelte new file mode 100644 index 000000000..55890b44e --- /dev/null +++ b/tests/fixtures/typescript/types/union_first_member_glued_block_comment_prettier_divergence/output_prettier.svelte @@ -0,0 +1,16 @@ + diff --git a/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/README.md b/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/README.md new file mode 100644 index 000000000..adb03612c --- /dev/null +++ b/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/README.md @@ -0,0 +1,43 @@ +# union_hug_leading_line_comment_prettier_divergence + +A **line** comment in the leading `|`→first-member gap of an otherwise *hugging* union +(`{ … } | null` — an object-like member with only void siblings). The comment must survive, +and it forces the union to expand. + +The hug prints its members inline (`{ a: 1 } | null`) and emits that leading gap block-only, +so a line comment there has nowhere to go — it would be **dropped**, silent content loss. It +could not be inlined regardless: a `//` runs to end-of-line and would swallow the member. So +the hug is declined and the union expands, which is what prettier does too. + +`union_prints_hugged` is the single source of truth for whether the hug actually happens, +because the union printer lays the members out while a **separate gate at each position that +can hold a union** decides whether to break after its keyword — and the two must agree. Asking +the bare syntactic `should_hug_union_type` at such a gate while the printer declines splits +them: the keyword keeps its operand glued (`type A = | // c⏎{ a: 1 }⏎| null`) while the members +explode below it, where a non-hugging union of the same shape correctly breaks after the +keyword. + +Every one of those positions is covered here, because the syntactic form is necessary but not +sufficient once a comment can change the printer's mind — and each gate that re-derived the +answer had drifted: + +- `=` — the type-alias RHS (`A`, `B`) +- `:` — an annotation (`d`), via `union_return_hugs` +- `=>` — a function-type return (`E`), same gate +- `as` — a cast (`f`), via `build_union_hanging_indent_doc` + +`g`/`H`/`i` are the controls: the same three positions with nothing to disqualify the hug, so +it still happens and the keyword stays glued. A **block** comment in the gap (`C`) also stays +hugged and inline — it renders fine there, nothing is lost, and prettier agrees. + +## The divergence + +Only the **encoding of the member offset**. Both formatters offset the member past the `|` by +prettier's per-member `align(2, …)` (`union-type.js`); prettier emits that 2-column offset as +`tab + 2 spaces` under `--use-tabs`, tsv rounds it up to one whole tab — the same visual width +at `tabWidth = 2`. Identical in kind to case A of +[union_intersection_parens_leading_line_comment](../union_intersection_parens_leading_line_comment_prettier_divergence/), +and not specific to the hug — any union member with a leading line comment shows it. + +See [conformance_prettier.md §Tabs-Only Alignment](../../../../../docs/conformance_prettier.md#tabs-only-alignment) +and the [Tabs-Only Indentation Philosophy](../../../../../docs/conformance_prettier.md#tabs-only-indentation-philosophy). diff --git a/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/expected.json b/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/expected.json new file mode 100644 index 000000000..3ee0a163d --- /dev/null +++ b/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/expected.json @@ -0,0 +1,1947 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 774, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " A line comment before a hugging object member must survive.", + "start": 20, + "end": 82, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 63 + } + } + }, + { + "type": "Line", + "value": " c", + "start": 97, + "end": 101, + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 8 + } + } + }, + { + "type": "Line", + "value": " A line comment before a hugging type-reference member must survive.", + "start": 126, + "end": 196, + "loc": { + "start": { + "line": 8, + "column": 1 + }, + "end": { + "line": 8, + "column": 71 + } + } + }, + { + "type": "Line", + "value": " c", + "start": 211, + "end": 215, + "loc": { + "start": { + "line": 10, + "column": 4 + }, + "end": { + "line": 10, + "column": 8 + } + } + }, + { + "type": "Line", + "value": " A block comment in the same position already survives.", + "start": 235, + "end": 292, + "loc": { + "start": { + "line": 14, + "column": 1 + }, + "end": { + "line": 14, + "column": 58 + } + } + }, + { + "type": "Block", + "value": " c ", + "start": 303, + "end": 310, + "loc": { + "start": { + "line": 15, + "column": 10 + }, + "end": { + "line": 15, + "column": 17 + } + } + }, + { + "type": "Line", + "value": " Every position that must agree with the printer about whether the hug happens", + "start": 330, + "end": 410, + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 81 + } + } + }, + { + "type": "Line", + "value": " breaks after its keyword, exactly as `=` does above.", + "start": 412, + "end": 467, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 56 + } + } + }, + { + "type": "Line", + "value": " c", + "start": 480, + "end": 484, + "loc": { + "start": { + "line": 20, + "column": 4 + }, + "end": { + "line": 20, + "column": 8 + } + } + }, + { + "type": "Line", + "value": " c", + "start": 528, + "end": 532, + "loc": { + "start": { + "line": 25, + "column": 4 + }, + "end": { + "line": 25, + "column": 8 + } + } + }, + { + "type": "Line", + "value": " c", + "start": 579, + "end": 583, + "loc": { + "start": { + "line": 30, + "column": 4 + }, + "end": { + "line": 30, + "column": 8 + } + } + }, + { + "type": "Line", + "value": " The same positions still hug when nothing disqualifies it.", + "start": 608, + "end": 669, + "loc": { + "start": { + "line": 34, + "column": 1 + }, + "end": { + "line": 34, + "column": 62 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 773, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 764, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 38, + "column": 9 + } + }, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start": 84, + "end": 123, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 6, + "column": 9 + } + }, + "id": { + "type": "Identifier", + "start": 89, + "end": 90, + "loc": { + "start": { + "line": 3, + "column": 6 + }, + "end": { + "line": 3, + "column": 7 + } + }, + "name": "A" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 95, + "end": 122, + "loc": { + "start": { + "line": 4, + "column": 2 + }, + "end": { + "line": 6, + "column": 8 + } + }, + "types": [ + { + "type": "TSTypeLiteral", + "start": 105, + "end": 113, + "loc": { + "start": { + "line": 5, + "column": 3 + }, + "end": { + "line": 5, + "column": 11 + } + }, + "members": [ + { + "type": "TSPropertySignature", + "start": 107, + "end": 111, + "loc": { + "start": { + "line": 5, + "column": 5 + }, + "end": { + "line": 5, + "column": 9 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 107, + "end": 108, + "loc": { + "start": { + "line": 5, + "column": 5 + }, + "end": { + "line": 5, + "column": 6 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 108, + "end": 111, + "loc": { + "start": { + "line": 5, + "column": 6 + }, + "end": { + "line": 5, + "column": 9 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 110, + "end": 111, + "loc": { + "start": { + "line": 5, + "column": 8 + }, + "end": { + "line": 5, + "column": 9 + } + }, + "literal": { + "type": "Literal", + "start": 110, + "end": 111, + "loc": { + "start": { + "line": 5, + "column": 8 + }, + "end": { + "line": 5, + "column": 9 + } + }, + "value": 1, + "raw": "1" + } + } + } + } + ], + "leadingComments": [ + { + "type": "Line", + "value": " c", + "start": 97, + "end": 101 + } + ] + }, + { + "type": "TSNullKeyword", + "start": 118, + "end": 122, + "loc": { + "start": { + "line": 6, + "column": 4 + }, + "end": { + "line": 6, + "column": 8 + } + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A line comment before a hugging object member must survive.", + "start": 20, + "end": 82 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 198, + "end": 232, + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 12, + "column": 9 + } + }, + "id": { + "type": "Identifier", + "start": 203, + "end": 204, + "loc": { + "start": { + "line": 9, + "column": 6 + }, + "end": { + "line": 9, + "column": 7 + } + }, + "name": "B" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 209, + "end": 231, + "loc": { + "start": { + "line": 10, + "column": 2 + }, + "end": { + "line": 12, + "column": 8 + } + }, + "types": [ + { + "type": "TSTypeReference", + "start": 219, + "end": 222, + "loc": { + "start": { + "line": 11, + "column": 3 + }, + "end": { + "line": 11, + "column": 6 + } + }, + "typeName": { + "type": "Identifier", + "start": 219, + "end": 222, + "loc": { + "start": { + "line": 11, + "column": 3 + }, + "end": { + "line": 11, + "column": 6 + } + }, + "name": "Foo" + }, + "leadingComments": [ + { + "type": "Line", + "value": " c", + "start": 211, + "end": 215 + } + ] + }, + { + "type": "TSNullKeyword", + "start": 227, + "end": 231, + "loc": { + "start": { + "line": 12, + "column": 4 + }, + "end": { + "line": 12, + "column": 8 + } + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A line comment before a hugging type-reference member must survive.", + "start": 126, + "end": 196 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 294, + "end": 327, + "loc": { + "start": { + "line": 15, + "column": 1 + }, + "end": { + "line": 15, + "column": 34 + } + }, + "id": { + "type": "Identifier", + "start": 299, + "end": 300, + "loc": { + "start": { + "line": 15, + "column": 6 + }, + "end": { + "line": 15, + "column": 7 + } + }, + "name": "C" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 311, + "end": 326, + "loc": { + "start": { + "line": 15, + "column": 18 + }, + "end": { + "line": 15, + "column": 33 + } + }, + "types": [ + { + "type": "TSTypeLiteral", + "start": 311, + "end": 319, + "loc": { + "start": { + "line": 15, + "column": 18 + }, + "end": { + "line": 15, + "column": 26 + } + }, + "members": [ + { + "type": "TSPropertySignature", + "start": 313, + "end": 317, + "loc": { + "start": { + "line": 15, + "column": 20 + }, + "end": { + "line": 15, + "column": 24 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 313, + "end": 314, + "loc": { + "start": { + "line": 15, + "column": 20 + }, + "end": { + "line": 15, + "column": 21 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 314, + "end": 317, + "loc": { + "start": { + "line": 15, + "column": 21 + }, + "end": { + "line": 15, + "column": 24 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 316, + "end": 317, + "loc": { + "start": { + "line": 15, + "column": 23 + }, + "end": { + "line": 15, + "column": 24 + } + }, + "literal": { + "type": "Literal", + "start": 316, + "end": 317, + "loc": { + "start": { + "line": 15, + "column": 23 + }, + "end": { + "line": 15, + "column": 24 + } + }, + "value": 1, + "raw": "1" + } + } + } + } + ] + }, + { + "type": "TSNullKeyword", + "start": 322, + "end": 326, + "loc": { + "start": { + "line": 15, + "column": 29 + }, + "end": { + "line": 15, + "column": 33 + } + } + } + ], + "leadingComments": [ + { + "type": "Block", + "value": " c ", + "start": 303, + "end": 310 + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " A block comment in the same position already survives.", + "start": 235, + "end": 292 + } + ] + }, + { + "type": "VariableDeclaration", + "start": 469, + "end": 506, + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 22, + "column": 9 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 473, + "end": 505, + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 22, + "column": 8 + } + }, + "id": { + "type": "Identifier", + "start": 473, + "end": 505, + "loc": { + "start": { + "line": 19, + "column": 5 + }, + "end": { + "line": 22, + "column": 8 + } + }, + "name": "d", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 474, + "end": 505, + "loc": { + "start": { + "line": 19, + "column": 6 + }, + "end": { + "line": 22, + "column": 8 + } + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 478, + "end": 505, + "loc": { + "start": { + "line": 20, + "column": 2 + }, + "end": { + "line": 22, + "column": 8 + } + }, + "types": [ + { + "type": "TSTypeLiteral", + "start": 488, + "end": 496, + "loc": { + "start": { + "line": 21, + "column": 3 + }, + "end": { + "line": 21, + "column": 11 + } + }, + "members": [ + { + "type": "TSPropertySignature", + "start": 490, + "end": 494, + "loc": { + "start": { + "line": 21, + "column": 5 + }, + "end": { + "line": 21, + "column": 9 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 490, + "end": 491, + "loc": { + "start": { + "line": 21, + "column": 5 + }, + "end": { + "line": 21, + "column": 6 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 491, + "end": 494, + "loc": { + "start": { + "line": 21, + "column": 6 + }, + "end": { + "line": 21, + "column": 9 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 493, + "end": 494, + "loc": { + "start": { + "line": 21, + "column": 8 + }, + "end": { + "line": 21, + "column": 9 + } + }, + "literal": { + "type": "Literal", + "start": 493, + "end": 494, + "loc": { + "start": { + "line": 21, + "column": 8 + }, + "end": { + "line": 21, + "column": 9 + } + }, + "value": 1, + "raw": "1" + } + } + } + } + ], + "leadingComments": [ + { + "type": "Line", + "value": " c", + "start": 480, + "end": 484 + } + ] + }, + { + "type": "TSNullKeyword", + "start": 501, + "end": 505, + "loc": { + "start": { + "line": 22, + "column": 4 + }, + "end": { + "line": 22, + "column": 8 + } + } + } + ] + } + } + }, + "init": null + } + ], + "kind": "let", + "leadingComments": [ + { + "type": "Line", + "value": " Every position that must agree with the printer about whether the hug happens", + "start": 330, + "end": 410 + }, + { + "type": "Line", + "value": " breaks after its keyword, exactly as `=` does above.", + "start": 412, + "end": 467 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 509, + "end": 554, + "loc": { + "start": { + "line": 24, + "column": 1 + }, + "end": { + "line": 27, + "column": 9 + } + }, + "id": { + "type": "Identifier", + "start": 514, + "end": 515, + "loc": { + "start": { + "line": 24, + "column": 6 + }, + "end": { + "line": 24, + "column": 7 + } + }, + "name": "E" + }, + "typeAnnotation": { + "type": "TSFunctionType", + "start": 518, + "end": 553, + "loc": { + "start": { + "line": 24, + "column": 10 + }, + "end": { + "line": 27, + "column": 8 + } + }, + "parameters": [], + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 521, + "end": 553, + "loc": { + "start": { + "line": 24, + "column": 13 + }, + "end": { + "line": 27, + "column": 8 + } + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 526, + "end": 553, + "loc": { + "start": { + "line": 25, + "column": 2 + }, + "end": { + "line": 27, + "column": 8 + } + }, + "types": [ + { + "type": "TSTypeLiteral", + "start": 536, + "end": 544, + "loc": { + "start": { + "line": 26, + "column": 3 + }, + "end": { + "line": 26, + "column": 11 + } + }, + "members": [ + { + "type": "TSPropertySignature", + "start": 538, + "end": 542, + "loc": { + "start": { + "line": 26, + "column": 5 + }, + "end": { + "line": 26, + "column": 9 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 538, + "end": 539, + "loc": { + "start": { + "line": 26, + "column": 5 + }, + "end": { + "line": 26, + "column": 6 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 539, + "end": 542, + "loc": { + "start": { + "line": 26, + "column": 6 + }, + "end": { + "line": 26, + "column": 9 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 541, + "end": 542, + "loc": { + "start": { + "line": 26, + "column": 8 + }, + "end": { + "line": 26, + "column": 9 + } + }, + "literal": { + "type": "Literal", + "start": 541, + "end": 542, + "loc": { + "start": { + "line": 26, + "column": 8 + }, + "end": { + "line": 26, + "column": 9 + } + }, + "value": 1, + "raw": "1" + } + } + } + } + ], + "leadingComments": [ + { + "type": "Line", + "value": " c", + "start": 528, + "end": 532 + } + ] + }, + { + "type": "TSNullKeyword", + "start": 549, + "end": 553, + "loc": { + "start": { + "line": 27, + "column": 4 + }, + "end": { + "line": 27, + "column": 8 + } + } + } + ] + } + } + } + }, + { + "type": "VariableDeclaration", + "start": 557, + "end": 605, + "loc": { + "start": { + "line": 29, + "column": 1 + }, + "end": { + "line": 32, + "column": 9 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 563, + "end": 604, + "loc": { + "start": { + "line": 29, + "column": 7 + }, + "end": { + "line": 32, + "column": 8 + } + }, + "id": { + "type": "Identifier", + "start": 563, + "end": 564, + "loc": { + "start": { + "line": 29, + "column": 7 + }, + "end": { + "line": 29, + "column": 8 + } + }, + "name": "f" + }, + "init": { + "type": "TSAsExpression", + "start": 567, + "end": 604, + "loc": { + "start": { + "line": 29, + "column": 11 + }, + "end": { + "line": 32, + "column": 8 + } + }, + "expression": { + "type": "Identifier", + "start": 567, + "end": 571, + "loc": { + "start": { + "line": 29, + "column": 11 + }, + "end": { + "line": 29, + "column": 15 + } + }, + "name": "expr" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 577, + "end": 604, + "loc": { + "start": { + "line": 30, + "column": 2 + }, + "end": { + "line": 32, + "column": 8 + } + }, + "types": [ + { + "type": "TSTypeLiteral", + "start": 587, + "end": 595, + "loc": { + "start": { + "line": 31, + "column": 3 + }, + "end": { + "line": 31, + "column": 11 + } + }, + "members": [ + { + "type": "TSPropertySignature", + "start": 589, + "end": 593, + "loc": { + "start": { + "line": 31, + "column": 5 + }, + "end": { + "line": 31, + "column": 9 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 589, + "end": 590, + "loc": { + "start": { + "line": 31, + "column": 5 + }, + "end": { + "line": 31, + "column": 6 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 590, + "end": 593, + "loc": { + "start": { + "line": 31, + "column": 6 + }, + "end": { + "line": 31, + "column": 9 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 592, + "end": 593, + "loc": { + "start": { + "line": 31, + "column": 8 + }, + "end": { + "line": 31, + "column": 9 + } + }, + "literal": { + "type": "Literal", + "start": 592, + "end": 593, + "loc": { + "start": { + "line": 31, + "column": 8 + }, + "end": { + "line": 31, + "column": 9 + } + }, + "value": 1, + "raw": "1" + } + } + } + } + ], + "leadingComments": [ + { + "type": "Line", + "value": " c", + "start": 579, + "end": 583 + } + ] + }, + { + "type": "TSNullKeyword", + "start": 600, + "end": 604, + "loc": { + "start": { + "line": 32, + "column": 4 + }, + "end": { + "line": 32, + "column": 8 + } + } + } + ] + } + } + } + ], + "kind": "const" + }, + { + "type": "VariableDeclaration", + "start": 671, + "end": 694, + "loc": { + "start": { + "line": 35, + "column": 1 + }, + "end": { + "line": 35, + "column": 24 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 675, + "end": 693, + "loc": { + "start": { + "line": 35, + "column": 5 + }, + "end": { + "line": 35, + "column": 23 + } + }, + "id": { + "type": "Identifier", + "start": 675, + "end": 693, + "loc": { + "start": { + "line": 35, + "column": 5 + }, + "end": { + "line": 35, + "column": 23 + } + }, + "name": "g", + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 676, + "end": 693, + "loc": { + "start": { + "line": 35, + "column": 6 + }, + "end": { + "line": 35, + "column": 23 + } + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 678, + "end": 693, + "loc": { + "start": { + "line": 35, + "column": 8 + }, + "end": { + "line": 35, + "column": 23 + } + }, + "types": [ + { + "type": "TSTypeLiteral", + "start": 678, + "end": 686, + "loc": { + "start": { + "line": 35, + "column": 8 + }, + "end": { + "line": 35, + "column": 16 + } + }, + "members": [ + { + "type": "TSPropertySignature", + "start": 680, + "end": 684, + "loc": { + "start": { + "line": 35, + "column": 10 + }, + "end": { + "line": 35, + "column": 14 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 680, + "end": 681, + "loc": { + "start": { + "line": 35, + "column": 10 + }, + "end": { + "line": 35, + "column": 11 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 681, + "end": 684, + "loc": { + "start": { + "line": 35, + "column": 11 + }, + "end": { + "line": 35, + "column": 14 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 683, + "end": 684, + "loc": { + "start": { + "line": 35, + "column": 13 + }, + "end": { + "line": 35, + "column": 14 + } + }, + "literal": { + "type": "Literal", + "start": 683, + "end": 684, + "loc": { + "start": { + "line": 35, + "column": 13 + }, + "end": { + "line": 35, + "column": 14 + } + }, + "value": 1, + "raw": "1" + } + } + } + } + ] + }, + { + "type": "TSNullKeyword", + "start": 689, + "end": 693, + "loc": { + "start": { + "line": 35, + "column": 19 + }, + "end": { + "line": 35, + "column": 23 + } + } + } + ] + } + } + }, + "init": null + } + ], + "kind": "let", + "leadingComments": [ + { + "type": "Line", + "value": " The same positions still hug when nothing disqualifies it.", + "start": 608, + "end": 669 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 696, + "end": 727, + "loc": { + "start": { + "line": 36, + "column": 1 + }, + "end": { + "line": 36, + "column": 32 + } + }, + "id": { + "type": "Identifier", + "start": 701, + "end": 702, + "loc": { + "start": { + "line": 36, + "column": 6 + }, + "end": { + "line": 36, + "column": 7 + } + }, + "name": "H" + }, + "typeAnnotation": { + "type": "TSFunctionType", + "start": 705, + "end": 726, + "loc": { + "start": { + "line": 36, + "column": 10 + }, + "end": { + "line": 36, + "column": 31 + } + }, + "parameters": [], + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 708, + "end": 726, + "loc": { + "start": { + "line": 36, + "column": 13 + }, + "end": { + "line": 36, + "column": 31 + } + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 711, + "end": 726, + "loc": { + "start": { + "line": 36, + "column": 16 + }, + "end": { + "line": 36, + "column": 31 + } + }, + "types": [ + { + "type": "TSTypeLiteral", + "start": 711, + "end": 719, + "loc": { + "start": { + "line": 36, + "column": 16 + }, + "end": { + "line": 36, + "column": 24 + } + }, + "members": [ + { + "type": "TSPropertySignature", + "start": 713, + "end": 717, + "loc": { + "start": { + "line": 36, + "column": 18 + }, + "end": { + "line": 36, + "column": 22 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 713, + "end": 714, + "loc": { + "start": { + "line": 36, + "column": 18 + }, + "end": { + "line": 36, + "column": 19 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 714, + "end": 717, + "loc": { + "start": { + "line": 36, + "column": 19 + }, + "end": { + "line": 36, + "column": 22 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 716, + "end": 717, + "loc": { + "start": { + "line": 36, + "column": 21 + }, + "end": { + "line": 36, + "column": 22 + } + }, + "literal": { + "type": "Literal", + "start": 716, + "end": 717, + "loc": { + "start": { + "line": 36, + "column": 21 + }, + "end": { + "line": 36, + "column": 22 + } + }, + "value": 1, + "raw": "1" + } + } + } + } + ] + }, + { + "type": "TSNullKeyword", + "start": 722, + "end": 726, + "loc": { + "start": { + "line": 36, + "column": 27 + }, + "end": { + "line": 36, + "column": 31 + } + } + } + ] + } + } + } + }, + { + "type": "VariableDeclaration", + "start": 729, + "end": 763, + "loc": { + "start": { + "line": 37, + "column": 1 + }, + "end": { + "line": 37, + "column": 35 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 735, + "end": 762, + "loc": { + "start": { + "line": 37, + "column": 7 + }, + "end": { + "line": 37, + "column": 34 + } + }, + "id": { + "type": "Identifier", + "start": 735, + "end": 736, + "loc": { + "start": { + "line": 37, + "column": 7 + }, + "end": { + "line": 37, + "column": 8 + } + }, + "name": "i" + }, + "init": { + "type": "TSAsExpression", + "start": 739, + "end": 762, + "loc": { + "start": { + "line": 37, + "column": 11 + }, + "end": { + "line": 37, + "column": 34 + } + }, + "expression": { + "type": "Identifier", + "start": 739, + "end": 743, + "loc": { + "start": { + "line": 37, + "column": 11 + }, + "end": { + "line": 37, + "column": 15 + } + }, + "name": "expr" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 747, + "end": 762, + "loc": { + "start": { + "line": 37, + "column": 19 + }, + "end": { + "line": 37, + "column": 34 + } + }, + "types": [ + { + "type": "TSTypeLiteral", + "start": 747, + "end": 755, + "loc": { + "start": { + "line": 37, + "column": 19 + }, + "end": { + "line": 37, + "column": 27 + } + }, + "members": [ + { + "type": "TSPropertySignature", + "start": 749, + "end": 753, + "loc": { + "start": { + "line": 37, + "column": 21 + }, + "end": { + "line": 37, + "column": 25 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 749, + "end": 750, + "loc": { + "start": { + "line": 37, + "column": 21 + }, + "end": { + "line": 37, + "column": 22 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 750, + "end": 753, + "loc": { + "start": { + "line": 37, + "column": 22 + }, + "end": { + "line": 37, + "column": 25 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 752, + "end": 753, + "loc": { + "start": { + "line": 37, + "column": 24 + }, + "end": { + "line": 37, + "column": 25 + } + }, + "literal": { + "type": "Literal", + "start": 752, + "end": 753, + "loc": { + "start": { + "line": 37, + "column": 24 + }, + "end": { + "line": 37, + "column": 25 + } + }, + "value": 1, + "raw": "1" + } + } + } + } + ] + }, + { + "type": "TSNullKeyword", + "start": 758, + "end": 762, + "loc": { + "start": { + "line": 37, + "column": 30 + }, + "end": { + "line": 37, + "column": 34 + } + } + } + ] + } + } + } + ], + "kind": "const" + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/input.svelte b/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/input.svelte new file mode 100644 index 000000000..a6d9c98ea --- /dev/null +++ b/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/input.svelte @@ -0,0 +1,38 @@ + diff --git a/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/output_prettier.svelte b/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/output_prettier.svelte new file mode 100644 index 000000000..95f92f8c2 --- /dev/null +++ b/tests/fixtures/typescript/types/union_hug_leading_line_comment_prettier_divergence/output_prettier.svelte @@ -0,0 +1,38 @@ + diff --git a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/expected.json b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/expected.json new file mode 100644 index 000000000..7edb597a7 --- /dev/null +++ b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/expected.json @@ -0,0 +1,1064 @@ +{ + "css": null, + "js": [], + "start": 0, + "end": 512, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [] + }, + "options": null, + "comments": [ + { + "type": "Line", + "value": " case A: later union member with leading line comment - relocates to trail the", + "start": 20, + "end": 100, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 81 + } + } + }, + { + "type": "Line", + "value": " previous member", + "start": 102, + "end": 120, + "loc": { + "start": { + "line": 3, + "column": 1 + }, + "end": { + "line": 3, + "column": 19 + } + } + }, + { + "type": "Line", + "value": " leading", + "start": 137, + "end": 147, + "loc": { + "start": { + "line": 5, + "column": 6 + }, + "end": { + "line": 5, + "column": 16 + } + } + }, + { + "type": "Line", + "value": " case B: paren retained (intersection in union)", + "start": 157, + "end": 206, + "loc": { + "start": { + "line": 8, + "column": 1 + }, + "end": { + "line": 8, + "column": 50 + } + } + }, + { + "type": "Line", + "value": " leading", + "start": 223, + "end": 233, + "loc": { + "start": { + "line": 10, + "column": 6 + }, + "end": { + "line": 10, + "column": 16 + } + } + }, + { + "type": "Line", + "value": " case C: conditional extends", + "start": 249, + "end": 279, + "loc": { + "start": { + "line": 13, + "column": 1 + }, + "end": { + "line": 13, + "column": 31 + } + } + }, + { + "type": "Line", + "value": " comment", + "start": 302, + "end": 312, + "loc": { + "start": { + "line": 14, + "column": 22 + }, + "end": { + "line": 14, + "column": 32 + } + } + }, + { + "type": "Line", + "value": " case M1: 3-member union, leading on middle", + "start": 328, + "end": 373, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 46 + } + } + }, + { + "type": "Line", + "value": " leading", + "start": 391, + "end": 401, + "loc": { + "start": { + "line": 20, + "column": 6 + }, + "end": { + "line": 20, + "column": 16 + } + } + }, + { + "type": "Line", + "value": " case M2: 3-member union, leading on last", + "start": 417, + "end": 460, + "loc": { + "start": { + "line": 24, + "column": 1 + }, + "end": { + "line": 24, + "column": 44 + } + } + }, + { + "type": "Line", + "value": " leading", + "start": 484, + "end": 494, + "loc": { + "start": { + "line": 27, + "column": 6 + }, + "end": { + "line": 27, + "column": 16 + } + } + } + ], + "instance": { + "type": "Script", + "start": 0, + "end": 511, + "context": "default", + "content": { + "type": "Program", + "start": 18, + "end": 502, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 29, + "column": 9 + } + }, + "body": [ + { + "type": "TSTypeAliasDeclaration", + "start": 122, + "end": 154, + "loc": { + "start": { + "line": 4, + "column": 1 + }, + "end": { + "line": 6, + "column": 6 + } + }, + "id": { + "type": "Identifier", + "start": 127, + "end": 128, + "loc": { + "start": { + "line": 4, + "column": 6 + }, + "end": { + "line": 4, + "column": 7 + } + }, + "name": "A" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 133, + "end": 153, + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 6, + "column": 5 + } + }, + "types": [ + { + "type": "TSTypeReference", + "start": 135, + "end": 136, + "loc": { + "start": { + "line": 5, + "column": 4 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 135, + "end": 136, + "loc": { + "start": { + "line": 5, + "column": 4 + }, + "end": { + "line": 5, + "column": 5 + } + }, + "name": "a" + }, + "trailingComments": [ + { + "type": "Line", + "value": " leading", + "start": 137, + "end": 147 + } + ] + }, + { + "type": "TSTypeReference", + "start": 152, + "end": 153, + "loc": { + "start": { + "line": 6, + "column": 4 + }, + "end": { + "line": 6, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 152, + "end": 153, + "loc": { + "start": { + "line": 6, + "column": 4 + }, + "end": { + "line": 6, + "column": 5 + } + }, + "name": "b" + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " case A: later union member with leading line comment - relocates to trail the", + "start": 20, + "end": 100 + }, + { + "type": "Line", + "value": " previous member", + "start": 102, + "end": 120 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 208, + "end": 246, + "loc": { + "start": { + "line": 9, + "column": 1 + }, + "end": { + "line": 11, + "column": 12 + } + }, + "id": { + "type": "Identifier", + "start": 213, + "end": 214, + "loc": { + "start": { + "line": 9, + "column": 6 + }, + "end": { + "line": 9, + "column": 7 + } + }, + "name": "B" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 219, + "end": 245, + "loc": { + "start": { + "line": 10, + "column": 2 + }, + "end": { + "line": 11, + "column": 11 + } + }, + "types": [ + { + "type": "TSTypeReference", + "start": 221, + "end": 222, + "loc": { + "start": { + "line": 10, + "column": 4 + }, + "end": { + "line": 10, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 221, + "end": 222, + "loc": { + "start": { + "line": 10, + "column": 4 + }, + "end": { + "line": 10, + "column": 5 + } + }, + "name": "a" + }, + "trailingComments": [ + { + "type": "Line", + "value": " leading", + "start": 223, + "end": 233 + } + ] + }, + { + "type": "TSParenthesizedType", + "start": 238, + "end": 245, + "loc": { + "start": { + "line": 11, + "column": 4 + }, + "end": { + "line": 11, + "column": 11 + } + }, + "typeAnnotation": { + "type": "TSIntersectionType", + "start": 239, + "end": 244, + "loc": { + "start": { + "line": 11, + "column": 5 + }, + "end": { + "line": 11, + "column": 10 + } + }, + "types": [ + { + "type": "TSTypeReference", + "start": 239, + "end": 240, + "loc": { + "start": { + "line": 11, + "column": 5 + }, + "end": { + "line": 11, + "column": 6 + } + }, + "typeName": { + "type": "Identifier", + "start": 239, + "end": 240, + "loc": { + "start": { + "line": 11, + "column": 5 + }, + "end": { + "line": 11, + "column": 6 + } + }, + "name": "b" + } + }, + { + "type": "TSTypeReference", + "start": 243, + "end": 244, + "loc": { + "start": { + "line": 11, + "column": 9 + }, + "end": { + "line": 11, + "column": 10 + } + }, + "typeName": { + "type": "Identifier", + "start": 243, + "end": 244, + "loc": { + "start": { + "line": 11, + "column": 9 + }, + "end": { + "line": 11, + "column": 10 + } + }, + "name": "c" + } + } + ] + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " case B: paren retained (intersection in union)", + "start": 157, + "end": 206 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 281, + "end": 325, + "loc": { + "start": { + "line": 14, + "column": 1 + }, + "end": { + "line": 16, + "column": 6 + } + }, + "id": { + "type": "Identifier", + "start": 286, + "end": 287, + "loc": { + "start": { + "line": 14, + "column": 6 + }, + "end": { + "line": 14, + "column": 7 + } + }, + "name": "C" + }, + "typeAnnotation": { + "type": "TSConditionalType", + "start": 290, + "end": 324, + "loc": { + "start": { + "line": 14, + "column": 10 + }, + "end": { + "line": 16, + "column": 5 + } + }, + "checkType": { + "type": "TSTypeReference", + "start": 290, + "end": 291, + "loc": { + "start": { + "line": 14, + "column": 10 + }, + "end": { + "line": 14, + "column": 11 + } + }, + "typeName": { + "type": "Identifier", + "start": 290, + "end": 291, + "loc": { + "start": { + "line": 14, + "column": 10 + }, + "end": { + "line": 14, + "column": 11 + } + }, + "name": "a" + } + }, + "extendsType": { + "type": "TSTypeReference", + "start": 300, + "end": 301, + "loc": { + "start": { + "line": 14, + "column": 20 + }, + "end": { + "line": 14, + "column": 21 + } + }, + "typeName": { + "type": "Identifier", + "start": 300, + "end": 301, + "loc": { + "start": { + "line": 14, + "column": 20 + }, + "end": { + "line": 14, + "column": 21 + } + }, + "name": "b" + }, + "trailingComments": [ + { + "type": "Line", + "value": " comment", + "start": 302, + "end": 312 + } + ] + }, + "trueType": { + "type": "TSTypeReference", + "start": 317, + "end": 318, + "loc": { + "start": { + "line": 15, + "column": 4 + }, + "end": { + "line": 15, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 317, + "end": 318, + "loc": { + "start": { + "line": 15, + "column": 4 + }, + "end": { + "line": 15, + "column": 5 + } + }, + "name": "c" + } + }, + "falseType": { + "type": "TSTypeReference", + "start": 323, + "end": 324, + "loc": { + "start": { + "line": 16, + "column": 4 + }, + "end": { + "line": 16, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 323, + "end": 324, + "loc": { + "start": { + "line": 16, + "column": 4 + }, + "end": { + "line": 16, + "column": 5 + } + }, + "name": "d" + } + } + }, + "leadingComments": [ + { + "type": "Line", + "value": " case C: conditional extends", + "start": 249, + "end": 279 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 375, + "end": 414, + "loc": { + "start": { + "line": 19, + "column": 1 + }, + "end": { + "line": 22, + "column": 6 + } + }, + "id": { + "type": "Identifier", + "start": 380, + "end": 382, + "loc": { + "start": { + "line": 19, + "column": 6 + }, + "end": { + "line": 19, + "column": 8 + } + }, + "name": "M1" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 387, + "end": 413, + "loc": { + "start": { + "line": 20, + "column": 2 + }, + "end": { + "line": 22, + "column": 5 + } + }, + "types": [ + { + "type": "TSTypeReference", + "start": 389, + "end": 390, + "loc": { + "start": { + "line": 20, + "column": 4 + }, + "end": { + "line": 20, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 389, + "end": 390, + "loc": { + "start": { + "line": 20, + "column": 4 + }, + "end": { + "line": 20, + "column": 5 + } + }, + "name": "a" + }, + "trailingComments": [ + { + "type": "Line", + "value": " leading", + "start": 391, + "end": 401 + } + ] + }, + { + "type": "TSTypeReference", + "start": 406, + "end": 407, + "loc": { + "start": { + "line": 21, + "column": 4 + }, + "end": { + "line": 21, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 406, + "end": 407, + "loc": { + "start": { + "line": 21, + "column": 4 + }, + "end": { + "line": 21, + "column": 5 + } + }, + "name": "b" + } + }, + { + "type": "TSTypeReference", + "start": 412, + "end": 413, + "loc": { + "start": { + "line": 22, + "column": 4 + }, + "end": { + "line": 22, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 412, + "end": 413, + "loc": { + "start": { + "line": 22, + "column": 4 + }, + "end": { + "line": 22, + "column": 5 + } + }, + "name": "c" + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " case M1: 3-member union, leading on middle", + "start": 328, + "end": 373 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 462, + "end": 501, + "loc": { + "start": { + "line": 25, + "column": 1 + }, + "end": { + "line": 28, + "column": 6 + } + }, + "id": { + "type": "Identifier", + "start": 467, + "end": 469, + "loc": { + "start": { + "line": 25, + "column": 6 + }, + "end": { + "line": 25, + "column": 8 + } + }, + "name": "M2" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 474, + "end": 500, + "loc": { + "start": { + "line": 26, + "column": 2 + }, + "end": { + "line": 28, + "column": 5 + } + }, + "types": [ + { + "type": "TSTypeReference", + "start": 476, + "end": 477, + "loc": { + "start": { + "line": 26, + "column": 4 + }, + "end": { + "line": 26, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 476, + "end": 477, + "loc": { + "start": { + "line": 26, + "column": 4 + }, + "end": { + "line": 26, + "column": 5 + } + }, + "name": "a" + } + }, + { + "type": "TSTypeReference", + "start": 482, + "end": 483, + "loc": { + "start": { + "line": 27, + "column": 4 + }, + "end": { + "line": 27, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 482, + "end": 483, + "loc": { + "start": { + "line": 27, + "column": 4 + }, + "end": { + "line": 27, + "column": 5 + } + }, + "name": "b" + }, + "trailingComments": [ + { + "type": "Line", + "value": " leading", + "start": 484, + "end": 494 + } + ] + }, + { + "type": "TSTypeReference", + "start": 499, + "end": 500, + "loc": { + "start": { + "line": 28, + "column": 4 + }, + "end": { + "line": 28, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 499, + "end": 500, + "loc": { + "start": { + "line": 28, + "column": 4 + }, + "end": { + "line": 28, + "column": 5 + } + }, + "name": "c" + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " case M2: 3-member union, leading on last", + "start": 417, + "end": 460 + } + ] + } + ], + "sourceType": "module" + }, + "attributes": [ + { + "type": "Attribute", + "start": 8, + "end": 17, + "name": "lang", + "name_loc": { + "start": { + "line": 1, + "column": 8, + "character": 8 + }, + "end": { + "line": 1, + "column": 12, + "character": 12 + } + }, + "value": [ + { + "start": 14, + "end": 16, + "type": "Text", + "raw": "ts", + "data": "ts" + } + ] + } + ] + } +} diff --git a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/input.svelte b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/input.svelte new file mode 100644 index 000000000..aae1916b7 --- /dev/null +++ b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/input.svelte @@ -0,0 +1,29 @@ + diff --git a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/unformatted_compact.svelte b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/unformatted_compact.svelte new file mode 100644 index 000000000..d059073c0 --- /dev/null +++ b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment/unformatted_compact.svelte @@ -0,0 +1,22 @@ + diff --git a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/README.md b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/README.md index 884ca61a3..512f96925 100644 --- a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/README.md +++ b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/README.md @@ -4,20 +4,53 @@ A **leading** line comment on a broken union member (`type A =\n\t| // leading\n\ta\n\t| b;`), where the comment forces the member onto its own line. -**tsv** keeps the member flush under the `|`, using whole-tab indentation only. -**Prettier** renders the union member's 2-column `align(2)` offset as `tabs + 2 -spaces` under `--use-tabs`, so the member sits two columns past the `|`. Both -forms are stable under their respective formatters. +Both formatters offset the member past the `|` by prettier's per-member +`align(2)` (`union-type.js`). **Prettier** renders that 2-column offset as `tabs + +2 spaces` under `--use-tabs`. **tsv** rounds it up to one whole tab. At +`tabWidth = 2` the two are the same visual width — only the representation +differs. Both forms are stable under their respective formatters. ## Reason Per the Tabs-Only Indentation Philosophy, tsv never mixes tabs with alignment -spaces — when a leading line comment forces a union member onto its own line, tsv -keeps it at the `|`'s own indent level rather than emitting prettier's `align(2)` -sub-tab offset. At `tabWidth = 2` the visual result is equivalent; only the -representation differs. The fixture covers the first member (A), multiple leading -comments (D), and a leading line + trailing block (E); the trailing-comment cases -(B, F, M1, M2) and the conditional `extends` case (G) match both formatters. +spaces: it renders the `align(2)` offset as a whole tab rather than prettier's +sub-tab `··`. The offset itself is *not* the divergence — dropping it would make +the member sit two columns shallower than prettier, which is a different layout +rather than a different encoding of the same one. + +The offset covers the leading-comment run **together with** the member, because the +member's own first line is placed by that run's `hardline` rather than by the `| ` +prefix — offsetting only the member would leave its first line one level shallower +than its own internal breaks. Prettier's `align(2, print())` has the same shape: +`print()` carries the leading comments, so the run and the type share one offset. + +What takes the offset is the **run**; the member keeps whatever +`build_union_member_offset_doc` gives it. Cases D and E are why that distinction +matters: an object literal and a default-paren member each supply their own indent +and decline the offset, so wrapping the *member* in it would push their bodies two +columns past prettier and leave their closing delimiter out of line with its opener +— a layout difference, not an encoding one. + +## Cases + +Every case here diverges: A is the plain member, B multiple leading comments, C a +leading line plus a trailing block, D an object-literal member, E a default-paren +member (an intersection with a trailing object). D and E break on **source** +multiline, not width, so this fixture is not width-sensitive. + +The cases that **match** prettier — a later member's in-paren comment relocating to +trail the previous member, and the conditional `extends` form — live in the +non-divergence sibling +[union_intersection_parens_leading_line_comment](../union_intersection_parens_leading_line_comment/). +They show no offset because their members have no internal breaks, so there is no +continuation line for the encoding to differ on; +[union_paren_member_long_line_comment](../comments/union_paren_member_long_line_comment_prettier_divergence/) +pins the case where a later member *does* break internally and the offset surfaces. + +Case E is authored with the comment **outside** the parens. The form with the +comment *inside* retained parens is a distinct stable form — tsv keeps it there, +pinned by +[union_intersection_retained_paren_leading_line_comment](../union_intersection_retained_paren_leading_line_comment_prettier_divergence/). See [conformance_prettier.md](../../../../../docs/conformance_prettier.md) §Tabs-Only Alignment. diff --git a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/expected.json b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/expected.json index 1f46d9e99..0742b175a 100644 --- a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/expected.json +++ b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/expected.json @@ -2,7 +2,7 @@ "css": null, "js": [], "start": 0, - "end": 731, + "end": 693, "type": "Root", "fragment": { "type": "Fragment", @@ -44,9 +44,9 @@ }, { "type": "Line", - "value": " case B: later union member with leading line comment", - "start": 114, - "end": 169, + "value": " case B: multiple leading line comments", + "start": 115, + "end": 156, "loc": { "start": { "line": 8, @@ -54,38 +54,6 @@ }, "end": { "line": 8, - "column": 56 - } - } - }, - { - "type": "Line", - "value": " leading", - "start": 186, - "end": 196, - "loc": { - "start": { - "line": 10, - "column": 6 - }, - "end": { - "line": 10, - "column": 16 - } - } - }, - { - "type": "Line", - "value": " case D: multiple leading line comments", - "start": 206, - "end": 247, - "loc": { - "start": { - "line": 13, - "column": 1 - }, - "end": { - "line": 13, "column": 42 } } @@ -93,15 +61,15 @@ { "type": "Line", "value": " c1", - "start": 262, - "end": 267, + "start": 171, + "end": 176, "loc": { "start": { - "line": 15, + "line": 10, "column": 4 }, "end": { - "line": 15, + "line": 10, "column": 9 } } @@ -109,31 +77,31 @@ { "type": "Line", "value": " c2", - "start": 270, - "end": 275, + "start": 180, + "end": 185, "loc": { "start": { - "line": 16, - "column": 2 + "line": 11, + "column": 3 }, "end": { - "line": 16, - "column": 7 + "line": 11, + "column": 8 } } }, { "type": "Line", - "value": " case E: leading line + trailing block", - "start": 289, - "end": 329, + "value": " case C: leading line + trailing block", + "start": 200, + "end": 240, "loc": { "start": { - "line": 20, + "line": 15, "column": 1 }, "end": { - "line": 20, + "line": 15, "column": 41 } } @@ -141,15 +109,15 @@ { "type": "Line", "value": " leading", - "start": 344, - "end": 354, + "start": 255, + "end": 265, "loc": { "start": { - "line": 22, + "line": 17, "column": 4 }, "end": { - "line": 22, + "line": 17, "column": 14 } } @@ -157,144 +125,112 @@ { "type": "Block", "value": " t ", - "start": 359, - "end": 366, + "start": 271, + "end": 278, "loc": { "start": { - "line": 23, - "column": 4 + "line": 18, + "column": 5 }, "end": { - "line": 23, - "column": 11 + "line": 18, + "column": 12 } } }, { "type": "Line", - "value": " case F: paren retained (intersection in union)", - "start": 376, - "end": 425, + "value": " case D: object-literal first member - the comment run takes the offset, and", + "start": 288, + "end": 366, "loc": { "start": { - "line": 26, + "line": 21, "column": 1 }, "end": { - "line": 26, - "column": 50 - } - } - }, - { - "type": "Line", - "value": " leading", - "start": 442, - "end": 452, - "loc": { - "start": { - "line": 28, - "column": 6 - }, - "end": { - "line": 28, - "column": 16 + "line": 21, + "column": 79 } } }, { "type": "Line", - "value": " case G: conditional extends", - "start": 468, - "end": 498, + "value": " the object's own lines sit at its own indent (closing `}` aligns with `{`)", + "start": 368, + "end": 445, "loc": { "start": { - "line": 31, + "line": 22, "column": 1 }, "end": { - "line": 31, - "column": 31 + "line": 22, + "column": 78 } } }, { "type": "Line", - "value": " comment", - "start": 521, - "end": 531, + "value": " leading", + "start": 460, + "end": 470, "loc": { "start": { - "line": 32, - "column": 22 + "line": 24, + "column": 4 }, "end": { - "line": 32, - "column": 32 + "line": 24, + "column": 14 } } }, { "type": "Line", - "value": " case M1: 3-member union, leading on middle", - "start": 547, - "end": 592, + "value": " case E: default-paren first member - same as D, the paren layout supplies", + "start": 510, + "end": 586, "loc": { "start": { - "line": 36, + "line": 31, "column": 1 }, "end": { - "line": 36, - "column": 46 - } - } - }, - { - "type": "Line", - "value": " leading", - "start": 610, - "end": 620, - "loc": { - "start": { - "line": 38, - "column": 6 - }, - "end": { - "line": 38, - "column": 16 + "line": 31, + "column": 77 } } }, { "type": "Line", - "value": " case M2: 3-member union, leading on last", - "start": 636, - "end": 679, + "value": " the member's own indent", + "start": 588, + "end": 614, "loc": { "start": { - "line": 42, + "line": 32, "column": 1 }, "end": { - "line": 42, - "column": 44 + "line": 32, + "column": 27 } } }, { "type": "Line", "value": " leading", - "start": 703, - "end": 713, + "start": 629, + "end": 639, "loc": { "start": { - "line": 45, - "column": 6 + "line": 34, + "column": 4 }, "end": { - "line": 45, - "column": 16 + "line": 34, + "column": 14 } } } @@ -302,19 +238,19 @@ "instance": { "type": "Script", "start": 0, - "end": 730, + "end": 692, "context": "default", "content": { "type": "Program", "start": 18, - "end": 721, + "end": 683, "loc": { "start": { "line": 1, "column": 0 }, "end": { - "line": 47, + "line": 40, "column": 9 } }, @@ -322,7 +258,7 @@ { "type": "TSTypeAliasDeclaration", "start": 77, - "end": 111, + "end": 112, "loc": { "start": { "line": 3, @@ -352,7 +288,7 @@ "typeAnnotation": { "type": "TSUnionType", "start": 88, - "end": 110, + "end": 111, "loc": { "start": { "line": 4, @@ -366,30 +302,30 @@ "types": [ { "type": "TSTypeReference", - "start": 103, - "end": 104, + "start": 104, + "end": 105, "loc": { "start": { "line": 5, - "column": 2 + "column": 3 }, "end": { "line": 5, - "column": 3 + "column": 4 } }, "typeName": { "type": "Identifier", - "start": 103, - "end": 104, + "start": 104, + "end": 105, "loc": { "start": { "line": 5, - "column": 2 + "column": 3 }, "end": { "line": 5, - "column": 3 + "column": 4 } }, "name": "a" @@ -405,8 +341,8 @@ }, { "type": "TSTypeReference", - "start": 109, - "end": 110, + "start": 110, + "end": 111, "loc": { "start": { "line": 6, @@ -419,8 +355,8 @@ }, "typeName": { "type": "Identifier", - "start": 109, - "end": 110, + "start": 110, + "end": 111, "loc": { "start": { "line": 6, @@ -447,22 +383,22 @@ }, { "type": "TSTypeAliasDeclaration", - "start": 171, - "end": 203, + "start": 158, + "end": 197, "loc": { "start": { "line": 9, "column": 1 }, "end": { - "line": 11, + "line": 13, "column": 6 } }, "id": { "type": "Identifier", - "start": 176, - "end": 177, + "start": 163, + "end": 164, "loc": { "start": { "line": 9, @@ -477,83 +413,89 @@ }, "typeAnnotation": { "type": "TSUnionType", - "start": 182, - "end": 202, + "start": 169, + "end": 196, "loc": { "start": { "line": 10, "column": 2 }, "end": { - "line": 11, + "line": 13, "column": 5 } }, "types": [ { "type": "TSTypeReference", - "start": 184, - "end": 185, + "start": 189, + "end": 190, "loc": { "start": { - "line": 10, - "column": 4 + "line": 12, + "column": 3 }, "end": { - "line": 10, - "column": 5 + "line": 12, + "column": 4 } }, "typeName": { "type": "Identifier", - "start": 184, - "end": 185, + "start": 189, + "end": 190, "loc": { "start": { - "line": 10, - "column": 4 + "line": 12, + "column": 3 }, "end": { - "line": 10, - "column": 5 + "line": 12, + "column": 4 } }, "name": "a" }, - "trailingComments": [ + "leadingComments": [ { "type": "Line", - "value": " leading", - "start": 186, - "end": 196 + "value": " c1", + "start": 171, + "end": 176 + }, + { + "type": "Line", + "value": " c2", + "start": 180, + "end": 185 } ] }, { "type": "TSTypeReference", - "start": 201, - "end": 202, + "start": 195, + "end": 196, "loc": { "start": { - "line": 11, + "line": 13, "column": 4 }, "end": { - "line": 11, + "line": 13, "column": 5 } }, "typeName": { "type": "Identifier", - "start": 201, - "end": 202, + "start": 195, + "end": 196, "loc": { "start": { - "line": 11, + "line": 13, "column": 4 }, "end": { - "line": 11, + "line": 13, "column": 5 } }, @@ -565,83 +507,83 @@ "leadingComments": [ { "type": "Line", - "value": " case B: later union member with leading line comment", - "start": 114, - "end": 169 + "value": " case B: multiple leading line comments", + "start": 115, + "end": 156 } ] }, { "type": "TSTypeAliasDeclaration", - "start": 249, - "end": 286, + "start": 242, + "end": 285, "loc": { "start": { - "line": 14, + "line": 16, "column": 1 }, "end": { - "line": 18, + "line": 19, "column": 6 } }, "id": { "type": "Identifier", - "start": 254, - "end": 255, + "start": 247, + "end": 248, "loc": { "start": { - "line": 14, + "line": 16, "column": 6 }, "end": { - "line": 14, + "line": 16, "column": 7 } }, - "name": "D" + "name": "C" }, "typeAnnotation": { "type": "TSUnionType", - "start": 260, - "end": 285, + "start": 253, + "end": 284, "loc": { "start": { - "line": 15, + "line": 17, "column": 2 }, "end": { - "line": 18, + "line": 19, "column": 5 } }, "types": [ { "type": "TSTypeReference", - "start": 278, - "end": 279, + "start": 269, + "end": 270, "loc": { "start": { - "line": 17, - "column": 2 + "line": 18, + "column": 3 }, "end": { - "line": 17, - "column": 3 + "line": 18, + "column": 4 } }, "typeName": { "type": "Identifier", - "start": 278, - "end": 279, + "start": 269, + "end": 270, "loc": { "start": { - "line": 17, - "column": 2 + "line": 18, + "column": 3 }, "end": { - "line": 17, - "column": 3 + "line": 18, + "column": 4 } }, "name": "a" @@ -649,43 +591,45 @@ "leadingComments": [ { "type": "Line", - "value": " c1", - "start": 262, - "end": 267 - }, + "value": " leading", + "start": 255, + "end": 265 + } + ], + "trailingComments": [ { - "type": "Line", - "value": " c2", - "start": 270, - "end": 275 + "type": "Block", + "value": " t ", + "start": 271, + "end": 278 } ] }, { "type": "TSTypeReference", - "start": 284, - "end": 285, + "start": 283, + "end": 284, "loc": { "start": { - "line": 18, + "line": 19, "column": 4 }, "end": { - "line": 18, + "line": 19, "column": 5 } }, "typeName": { "type": "Identifier", - "start": 284, - "end": 285, + "start": 283, + "end": 284, "loc": { "start": { - "line": 18, + "line": 19, "column": 4 }, "end": { - "line": 18, + "line": 19, "column": 5 } }, @@ -697,129 +641,265 @@ "leadingComments": [ { "type": "Line", - "value": " case D: multiple leading line comments", - "start": 206, - "end": 247 + "value": " case C: leading line + trailing block", + "start": 200, + "end": 240 } ] }, { "type": "TSTypeAliasDeclaration", - "start": 331, - "end": 373, + "start": 447, + "end": 507, "loc": { "start": { - "line": 21, + "line": 23, "column": 1 }, "end": { - "line": 24, + "line": 29, "column": 6 } }, "id": { "type": "Identifier", - "start": 336, - "end": 337, + "start": 452, + "end": 453, "loc": { "start": { - "line": 21, + "line": 23, "column": 6 }, "end": { - "line": 21, + "line": 23, "column": 7 } }, - "name": "E" + "name": "D" }, "typeAnnotation": { "type": "TSUnionType", - "start": 342, - "end": 372, + "start": 458, + "end": 506, "loc": { "start": { - "line": 22, + "line": 24, "column": 2 }, "end": { - "line": 24, + "line": 29, "column": 5 } }, "types": [ { - "type": "TSTypeReference", - "start": 357, - "end": 358, + "type": "TSTypeLiteral", + "start": 474, + "end": 500, "loc": { "start": { - "line": 23, - "column": 2 + "line": 25, + "column": 3 }, "end": { - "line": 23, - "column": 3 + "line": 28, + "column": 4 } }, - "typeName": { - "type": "Identifier", - "start": 357, - "end": 358, - "loc": { - "start": { - "line": 23, - "column": 2 + "members": [ + { + "type": "TSPropertySignature", + "start": 480, + "end": 485, + "loc": { + "start": { + "line": 26, + "column": 4 + }, + "end": { + "line": 26, + "column": 9 + } }, - "end": { - "line": 23, - "column": 3 + "computed": false, + "key": { + "type": "Identifier", + "start": 480, + "end": 481, + "loc": { + "start": { + "line": 26, + "column": 4 + }, + "end": { + "line": 26, + "column": 5 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 481, + "end": 484, + "loc": { + "start": { + "line": 26, + "column": 5 + }, + "end": { + "line": 26, + "column": 8 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 483, + "end": 484, + "loc": { + "start": { + "line": 26, + "column": 7 + }, + "end": { + "line": 26, + "column": 8 + } + }, + "literal": { + "type": "Literal", + "start": 483, + "end": 484, + "loc": { + "start": { + "line": 26, + "column": 7 + }, + "end": { + "line": 26, + "column": 8 + } + }, + "value": 1, + "raw": "1" + } + } } }, - "name": "a" - }, - "leadingComments": [ { - "type": "Line", - "value": " leading", - "start": 344, - "end": 354 + "type": "TSPropertySignature", + "start": 490, + "end": 495, + "loc": { + "start": { + "line": 27, + "column": 4 + }, + "end": { + "line": 27, + "column": 9 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 490, + "end": 491, + "loc": { + "start": { + "line": 27, + "column": 4 + }, + "end": { + "line": 27, + "column": 5 + } + }, + "name": "b" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 491, + "end": 494, + "loc": { + "start": { + "line": 27, + "column": 5 + }, + "end": { + "line": 27, + "column": 8 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 493, + "end": 494, + "loc": { + "start": { + "line": 27, + "column": 7 + }, + "end": { + "line": 27, + "column": 8 + } + }, + "literal": { + "type": "Literal", + "start": 493, + "end": 494, + "loc": { + "start": { + "line": 27, + "column": 7 + }, + "end": { + "line": 27, + "column": 8 + } + }, + "value": 2, + "raw": "2" + } + } + } } ], - "trailingComments": [ + "leadingComments": [ { - "type": "Block", - "value": " t ", - "start": 359, - "end": 366 + "type": "Line", + "value": " leading", + "start": 460, + "end": 470 } ] }, { "type": "TSTypeReference", - "start": 371, - "end": 372, + "start": 505, + "end": 506, "loc": { "start": { - "line": 24, + "line": 29, "column": 4 }, "end": { - "line": 24, + "line": 29, "column": 5 } }, "typeName": { "type": "Identifier", - "start": 371, - "end": 372, + "start": 505, + "end": 506, "loc": { "start": { - "line": 24, + "line": 29, "column": 4 }, "end": { - "line": 24, + "line": 29, "column": 5 } }, @@ -831,475 +911,313 @@ "leadingComments": [ { "type": "Line", - "value": " case E: leading line + trailing block", - "start": 289, - "end": 329 + "value": " case D: object-literal first member - the comment run takes the offset, and", + "start": 288, + "end": 366 + }, + { + "type": "Line", + "value": " the object's own lines sit at its own indent (closing `}` aligns with `{`)", + "start": 368, + "end": 445 } ] }, { "type": "TSTypeAliasDeclaration", - "start": 427, - "end": 465, + "start": 616, + "end": 682, "loc": { "start": { - "line": 27, + "line": 33, "column": 1 }, "end": { - "line": 29, - "column": 12 + "line": 39, + "column": 6 } }, "id": { "type": "Identifier", - "start": 432, - "end": 433, + "start": 621, + "end": 622, "loc": { "start": { - "line": 27, + "line": 33, "column": 6 }, "end": { - "line": 27, + "line": 33, "column": 7 } }, - "name": "F" + "name": "E" }, "typeAnnotation": { "type": "TSUnionType", - "start": 438, - "end": 464, + "start": 627, + "end": 681, "loc": { "start": { - "line": 28, + "line": 34, "column": 2 }, "end": { - "line": 29, - "column": 11 + "line": 39, + "column": 5 } }, "types": [ - { - "type": "TSTypeReference", - "start": 440, - "end": 441, - "loc": { - "start": { - "line": 28, - "column": 4 - }, - "end": { - "line": 28, - "column": 5 - } - }, - "typeName": { - "type": "Identifier", - "start": 440, - "end": 441, - "loc": { - "start": { - "line": 28, - "column": 4 - }, - "end": { - "line": 28, - "column": 5 - } - }, - "name": "a" - }, - "trailingComments": [ - { - "type": "Line", - "value": " leading", - "start": 442, - "end": 452 - } - ] - }, { "type": "TSParenthesizedType", - "start": 457, - "end": 464, + "start": 643, + "end": 675, "loc": { "start": { - "line": 29, - "column": 4 + "line": 35, + "column": 3 }, "end": { - "line": 29, - "column": 11 + "line": 38, + "column": 5 } }, "typeAnnotation": { "type": "TSIntersectionType", - "start": 458, - "end": 463, + "start": 644, + "end": 674, "loc": { "start": { - "line": 29, - "column": 5 + "line": 35, + "column": 4 }, "end": { - "line": 29, - "column": 10 + "line": 38, + "column": 4 } }, "types": [ { "type": "TSTypeReference", - "start": 458, - "end": 459, + "start": 644, + "end": 645, "loc": { "start": { - "line": 29, - "column": 5 + "line": 35, + "column": 4 }, "end": { - "line": 29, - "column": 6 + "line": 35, + "column": 5 } }, "typeName": { "type": "Identifier", - "start": 458, - "end": 459, + "start": 644, + "end": 645, "loc": { "start": { - "line": 29, - "column": 5 + "line": 35, + "column": 4 }, "end": { - "line": 29, - "column": 6 + "line": 35, + "column": 5 } }, - "name": "b" + "name": "a" } }, { - "type": "TSTypeReference", - "start": 462, - "end": 463, + "type": "TSTypeLiteral", + "start": 648, + "end": 674, "loc": { "start": { - "line": 29, - "column": 9 + "line": 35, + "column": 8 }, "end": { - "line": 29, - "column": 10 + "line": 38, + "column": 4 } }, - "typeName": { - "type": "Identifier", - "start": 462, - "end": 463, - "loc": { - "start": { - "line": 29, - "column": 9 + "members": [ + { + "type": "TSPropertySignature", + "start": 654, + "end": 659, + "loc": { + "start": { + "line": 36, + "column": 4 + }, + "end": { + "line": 36, + "column": 9 + } }, - "end": { - "line": 29, - "column": 10 + "computed": false, + "key": { + "type": "Identifier", + "start": 654, + "end": 655, + "loc": { + "start": { + "line": 36, + "column": 4 + }, + "end": { + "line": 36, + "column": 5 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 655, + "end": 658, + "loc": { + "start": { + "line": 36, + "column": 5 + }, + "end": { + "line": 36, + "column": 8 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 657, + "end": 658, + "loc": { + "start": { + "line": 36, + "column": 7 + }, + "end": { + "line": 36, + "column": 8 + } + }, + "literal": { + "type": "Literal", + "start": 657, + "end": 658, + "loc": { + "start": { + "line": 36, + "column": 7 + }, + "end": { + "line": 36, + "column": 8 + } + }, + "value": 1, + "raw": "1" + } + } } }, - "name": "c" - } + { + "type": "TSPropertySignature", + "start": 664, + "end": 669, + "loc": { + "start": { + "line": 37, + "column": 4 + }, + "end": { + "line": 37, + "column": 9 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 664, + "end": 665, + "loc": { + "start": { + "line": 37, + "column": 4 + }, + "end": { + "line": 37, + "column": 5 + } + }, + "name": "b" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 665, + "end": 668, + "loc": { + "start": { + "line": 37, + "column": 5 + }, + "end": { + "line": 37, + "column": 8 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 667, + "end": 668, + "loc": { + "start": { + "line": 37, + "column": 7 + }, + "end": { + "line": 37, + "column": 8 + } + }, + "literal": { + "type": "Literal", + "start": 667, + "end": 668, + "loc": { + "start": { + "line": 37, + "column": 7 + }, + "end": { + "line": 37, + "column": 8 + } + }, + "value": 2, + "raw": "2" + } + } + } + } + ] } ] - } - } - ] - }, - "leadingComments": [ - { - "type": "Line", - "value": " case F: paren retained (intersection in union)", - "start": 376, - "end": 425 - } - ] - }, - { - "type": "TSTypeAliasDeclaration", - "start": 500, - "end": 544, - "loc": { - "start": { - "line": 32, - "column": 1 - }, - "end": { - "line": 34, - "column": 6 - } - }, - "id": { - "type": "Identifier", - "start": 505, - "end": 506, - "loc": { - "start": { - "line": 32, - "column": 6 - }, - "end": { - "line": 32, - "column": 7 - } - }, - "name": "G" - }, - "typeAnnotation": { - "type": "TSConditionalType", - "start": 509, - "end": 543, - "loc": { - "start": { - "line": 32, - "column": 10 - }, - "end": { - "line": 34, - "column": 5 - } - }, - "checkType": { - "type": "TSTypeReference", - "start": 509, - "end": 510, - "loc": { - "start": { - "line": 32, - "column": 10 - }, - "end": { - "line": 32, - "column": 11 - } - }, - "typeName": { - "type": "Identifier", - "start": 509, - "end": 510, - "loc": { - "start": { - "line": 32, - "column": 10 - }, - "end": { - "line": 32, - "column": 11 - } - }, - "name": "a" - } - }, - "extendsType": { - "type": "TSTypeReference", - "start": 519, - "end": 520, - "loc": { - "start": { - "line": 32, - "column": 20 - }, - "end": { - "line": 32, - "column": 21 - } - }, - "typeName": { - "type": "Identifier", - "start": 519, - "end": 520, - "loc": { - "start": { - "line": 32, - "column": 20 - }, - "end": { - "line": 32, - "column": 21 - } }, - "name": "b" - }, - "trailingComments": [ - { - "type": "Line", - "value": " comment", - "start": 521, - "end": 531 - } - ] - }, - "trueType": { - "type": "TSTypeReference", - "start": 536, - "end": 537, - "loc": { - "start": { - "line": 33, - "column": 4 - }, - "end": { - "line": 33, - "column": 5 - } - }, - "typeName": { - "type": "Identifier", - "start": 536, - "end": 537, - "loc": { - "start": { - "line": 33, - "column": 4 - }, - "end": { - "line": 33, - "column": 5 - } - }, - "name": "c" - } - }, - "falseType": { - "type": "TSTypeReference", - "start": 542, - "end": 543, - "loc": { - "start": { - "line": 34, - "column": 4 - }, - "end": { - "line": 34, - "column": 5 - } - }, - "typeName": { - "type": "Identifier", - "start": 542, - "end": 543, - "loc": { - "start": { - "line": 34, - "column": 4 - }, - "end": { - "line": 34, - "column": 5 - } - }, - "name": "d" - } - } - }, - "leadingComments": [ - { - "type": "Line", - "value": " case G: conditional extends", - "start": 468, - "end": 498 - } - ] - }, - { - "type": "TSTypeAliasDeclaration", - "start": 594, - "end": 633, - "loc": { - "start": { - "line": 37, - "column": 1 - }, - "end": { - "line": 40, - "column": 6 - } - }, - "id": { - "type": "Identifier", - "start": 599, - "end": 601, - "loc": { - "start": { - "line": 37, - "column": 6 - }, - "end": { - "line": 37, - "column": 8 - } - }, - "name": "M1" - }, - "typeAnnotation": { - "type": "TSUnionType", - "start": 606, - "end": 632, - "loc": { - "start": { - "line": 38, - "column": 2 - }, - "end": { - "line": 40, - "column": 5 - } - }, - "types": [ - { - "type": "TSTypeReference", - "start": 608, - "end": 609, - "loc": { - "start": { - "line": 38, - "column": 4 - }, - "end": { - "line": 38, - "column": 5 - } - }, - "typeName": { - "type": "Identifier", - "start": 608, - "end": 609, - "loc": { - "start": { - "line": 38, - "column": 4 - }, - "end": { - "line": 38, - "column": 5 - } - }, - "name": "a" - }, - "trailingComments": [ + "leadingComments": [ { "type": "Line", "value": " leading", - "start": 610, - "end": 620 + "start": 629, + "end": 639 } ] }, { "type": "TSTypeReference", - "start": 625, - "end": 626, + "start": 680, + "end": 681, "loc": { "start": { "line": 39, @@ -1312,8 +1230,8 @@ }, "typeName": { "type": "Identifier", - "start": 625, - "end": 626, + "start": 680, + "end": 681, "loc": { "start": { "line": 39, @@ -1326,203 +1244,21 @@ }, "name": "b" } - }, - { - "type": "TSTypeReference", - "start": 631, - "end": 632, - "loc": { - "start": { - "line": 40, - "column": 4 - }, - "end": { - "line": 40, - "column": 5 - } - }, - "typeName": { - "type": "Identifier", - "start": 631, - "end": 632, - "loc": { - "start": { - "line": 40, - "column": 4 - }, - "end": { - "line": 40, - "column": 5 - } - }, - "name": "c" - } } ] }, "leadingComments": [ { "type": "Line", - "value": " case M1: 3-member union, leading on middle", - "start": 547, - "end": 592 - } - ] - }, - { - "type": "TSTypeAliasDeclaration", - "start": 681, - "end": 720, - "loc": { - "start": { - "line": 43, - "column": 1 - }, - "end": { - "line": 46, - "column": 6 - } - }, - "id": { - "type": "Identifier", - "start": 686, - "end": 688, - "loc": { - "start": { - "line": 43, - "column": 6 - }, - "end": { - "line": 43, - "column": 8 - } + "value": " case E: default-paren first member - same as D, the paren layout supplies", + "start": 510, + "end": 586 }, - "name": "M2" - }, - "typeAnnotation": { - "type": "TSUnionType", - "start": 693, - "end": 719, - "loc": { - "start": { - "line": 44, - "column": 2 - }, - "end": { - "line": 46, - "column": 5 - } - }, - "types": [ - { - "type": "TSTypeReference", - "start": 695, - "end": 696, - "loc": { - "start": { - "line": 44, - "column": 4 - }, - "end": { - "line": 44, - "column": 5 - } - }, - "typeName": { - "type": "Identifier", - "start": 695, - "end": 696, - "loc": { - "start": { - "line": 44, - "column": 4 - }, - "end": { - "line": 44, - "column": 5 - } - }, - "name": "a" - } - }, - { - "type": "TSTypeReference", - "start": 701, - "end": 702, - "loc": { - "start": { - "line": 45, - "column": 4 - }, - "end": { - "line": 45, - "column": 5 - } - }, - "typeName": { - "type": "Identifier", - "start": 701, - "end": 702, - "loc": { - "start": { - "line": 45, - "column": 4 - }, - "end": { - "line": 45, - "column": 5 - } - }, - "name": "b" - }, - "trailingComments": [ - { - "type": "Line", - "value": " leading", - "start": 703, - "end": 713 - } - ] - }, - { - "type": "TSTypeReference", - "start": 718, - "end": 719, - "loc": { - "start": { - "line": 46, - "column": 4 - }, - "end": { - "line": 46, - "column": 5 - } - }, - "typeName": { - "type": "Identifier", - "start": 718, - "end": 719, - "loc": { - "start": { - "line": 46, - "column": 4 - }, - "end": { - "line": 46, - "column": 5 - } - }, - "name": "c" - } - } - ] - }, - "leadingComments": [ { "type": "Line", - "value": " case M2: 3-member union, leading on last", - "start": 636, - "end": 679 + "value": " the member's own indent", + "start": 588, + "end": 614 } ] } diff --git a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/input.svelte b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/input.svelte index 530f0afe1..a15dd6fc2 100644 --- a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/input.svelte +++ b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/input.svelte @@ -2,46 +2,39 @@ // case A: first union member with leading line comment type A = | // leading - a + a | b; - // case B: later union member with leading line comment + // case B: multiple leading line comments type B = - | a // leading + | // c1 + // c2 + a | b; - // case D: multiple leading line comments + // case C: leading line + trailing block + type C = + | // leading + a /* t */ + | b; + + // case D: object-literal first member - the comment run takes the offset, and + // the object's own lines sit at its own indent (closing `}` aligns with `{`) type D = - | // c1 - // c2 - a + | // leading + { + a: 1; + b: 2; + } | b; - // case E: leading line + trailing block + // case E: default-paren first member - same as D, the paren layout supplies + // the member's own indent type E = | // leading - a /* t */ + (a & { + a: 1; + b: 2; + }) | b; - - // case F: paren retained (intersection in union) - type F = - | a // leading - | (b & c); - - // case G: conditional extends - type G = a extends b // comment - ? c - : d; - - // case M1: 3-member union, leading on middle - type M1 = - | a // leading - | b - | c; - - // case M2: 3-member union, leading on last - type M2 = - | a - | b // leading - | c; diff --git a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/output_prettier.svelte b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/output_prettier.svelte index 14af01dce..2ad00c1b4 100644 --- a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/output_prettier.svelte +++ b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/output_prettier.svelte @@ -5,43 +5,36 @@ a | b; - // case B: later union member with leading line comment + // case B: multiple leading line comments type B = - | a // leading - | b; - - // case D: multiple leading line comments - type D = | // c1 // c2 a | b; - // case E: leading line + trailing block - type E = + // case C: leading line + trailing block + type C = | // leading a /* t */ | b; - // case F: paren retained (intersection in union) - type F = - | a // leading - | (b & c); - - // case G: conditional extends - type G = a extends b // comment - ? c - : d; - - // case M1: 3-member union, leading on middle - type M1 = - | a // leading - | b - | c; + // case D: object-literal first member - the comment run takes the offset, and + // the object's own lines sit at its own indent (closing `}` aligns with `{`) + type D = + | // leading + { + a: 1; + b: 2; + } + | b; - // case M2: 3-member union, leading on last - type M2 = - | a - | b // leading - | c; + // case E: default-paren first member - same as D, the paren layout supplies + // the member's own indent + type E = + | // leading + (a & { + a: 1; + b: 2; + }) + | b; diff --git a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/unformatted_ours_compact.svelte b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/unformatted_ours_compact.svelte index 1d5803f09..b51a180fc 100644 --- a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/unformatted_ours_compact.svelte +++ b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/unformatted_ours_compact.svelte @@ -3,32 +3,26 @@ type A=(// leading a)|b; - // case B: later union member with leading line comment - type B=a|(// leading - b); - - // case D: multiple leading line comments - type D=(// c1 + // case B: multiple leading line comments + type B=(// c1 // c2 a)|b; - // case E: leading line + trailing block - type E=(// leading + // case C: leading line + trailing block + type C=(// leading a/* t */)|b; - // case F: paren retained (intersection in union) - type F=a|(// leading - b&c); - - // case G: conditional extends - type G=a extends(// comment - b)?c:d; - - // case M1: 3-member union, leading on middle - type M1=a|(// leading - b)|c; + // case D: object-literal first member - the comment run takes the offset, and + // the object's own lines sit at its own indent (closing `}` aligns with `{`) + type D=(// leading + { + a:1;b:2 + })|b; - // case M2: 3-member union, leading on last - type M2=a|b|(// leading - c); + // case E: default-paren first member - same as D, the paren layout supplies + // the member's own indent + type E=|// leading + (a&{ + a:1;b:2 + })|b; diff --git a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/unformatted_ours_parens.svelte b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/unformatted_ours_parens.svelte index eb17cc314..8bd8e7fbc 100644 --- a/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/unformatted_ours_parens.svelte +++ b/tests/fixtures/typescript/types/union_intersection_parens_leading_line_comment_prettier_divergence/unformatted_ours_parens.svelte @@ -3,32 +3,28 @@ type A = (// leading a) | b; - // case B: later union member with leading line comment - type B = a | (// leading - b); - - // case D: multiple leading line comments - type D = (// c1 + // case B: multiple leading line comments + type B = (// c1 // c2 a) | b; - // case E: leading line + trailing block - type E = (// leading + // case C: leading line + trailing block + type C = (// leading a /* t */) | b; - // case F: paren retained (intersection in union) - type F = a | (// leading - b & c); - - // case G: conditional extends - type G = a extends (// comment - b) ? c : d; - - // case M1: 3-member union, leading on middle - type M1 = a | (// leading - b) | c; + // case D: object-literal first member - the comment run takes the offset, and + // the object's own lines sit at its own indent (closing `}` aligns with `{`) + type D = (// leading + { + a: 1; + b: 2; + }) | b; - // case M2: 3-member union, leading on last - type M2 = a | b | (// leading - c); + // case E: default-paren first member - same as D, the paren layout supplies + // the member's own indent + type E = | // leading + (a & { + a: 1; + b: 2; + }) | b; diff --git a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/README.md b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/README.md index fd8ddc9e1..44ac451f8 100644 --- a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/README.md +++ b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/README.md @@ -14,6 +14,18 @@ stays inline (`A | B`) when it fits. Per Comment Position Philosophy: the comment is inside the parenthesized member, so tsv associates it with that member rather than hoisting it out. +`FirstIntersection` is the same shape with a **paren-intersection** member whose +trailing object supplies its own aligned layout (`(// c\n A & { … })`). It is a +separate case because that layout is built from the *already-unwrapped* inner type, +so the paren's own `(`→inner gap is invisible to it and the comment has to be +threaded in explicitly — without that it is silently **dropped**, which no +prettier comparison catches (the two forms differ anyway) and only the print-once +comment ledger reports. Its comment hugs the `(` rather than taking its own line +below it, matching the other default-paren member shapes (function, constructor, +conditional, plain intersection); the paren-union `First` above is the one that +puts `(` and the comment on separate lines, because its layout gives `(` its own +line whenever the group breaks. + This mirrors the trailing-comment sibling [union_intersection_retained_paren_line_comment](../union_intersection_retained_paren_line_comment_prettier_divergence/), which likewise keeps a line comment inside the retained parens for the first diff --git a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/expected.json b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/expected.json index 87f7bb43f..cde3486a7 100644 --- a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/expected.json +++ b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/expected.json @@ -2,7 +2,7 @@ "css": null, "js": [], "start": 0, - "end": 533, + "end": 815, "type": "Root", "fragment": { "type": "Fragment", @@ -76,9 +76,9 @@ }, { "type": "Line", - "value": " a leading line comment inside a LATER member's parens relocates to trail the", + "value": " first member is a retained-paren intersection with a trailing object, which", "start": 273, - "end": 352, + "end": 351, "loc": { "start": { "line": 12, @@ -86,15 +86,15 @@ }, "end": { "line": 12, - "column": 80 + "column": 79 } } }, { "type": "Line", - "value": " previous member; only the first member - with no previous member to relocate", - "start": 354, - "end": 433, + "value": " supplies its own aligned layout - the comment is kept inside the parens the same", + "start": 353, + "end": 436, "loc": { "start": { "line": 13, @@ -102,15 +102,15 @@ }, "end": { "line": 13, - "column": 80 + "column": 84 } } }, { "type": "Line", - "value": " onto - keeps the comment inside the parens", - "start": 435, - "end": 480, + "value": " way, hugging the `(` above the intersection", + "start": 438, + "end": 484, "loc": { "start": { "line": 14, @@ -118,22 +118,86 @@ }, "end": { "line": 14, - "column": 46 + "column": 47 } } }, { "type": "Line", "value": " c", - "start": 499, - "end": 503, + "start": 516, + "end": 520, "loc": { "start": { "line": 16, - "column": 6 + "column": 5 }, "end": { "line": 16, + "column": 9 + } + } + }, + { + "type": "Line", + "value": " a leading line comment inside a LATER member's parens relocates to trail the", + "start": 555, + "end": 634, + "loc": { + "start": { + "line": 22, + "column": 1 + }, + "end": { + "line": 22, + "column": 80 + } + } + }, + { + "type": "Line", + "value": " previous member; only the first member - with no previous member to relocate", + "start": 636, + "end": 715, + "loc": { + "start": { + "line": 23, + "column": 1 + }, + "end": { + "line": 23, + "column": 80 + } + } + }, + { + "type": "Line", + "value": " onto - keeps the comment inside the parens", + "start": 717, + "end": 762, + "loc": { + "start": { + "line": 24, + "column": 1 + }, + "end": { + "line": 24, + "column": 46 + } + } + }, + { + "type": "Line", + "value": " c", + "start": 781, + "end": 785, + "loc": { + "start": { + "line": 26, + "column": 6 + }, + "end": { + "line": 26, "column": 10 } } @@ -142,19 +206,19 @@ "instance": { "type": "Script", "start": 0, - "end": 532, + "end": 814, "context": "default", "content": { "type": "Program", "start": 18, - "end": 523, + "end": 805, "loc": { "start": { "line": 1, "column": 0 }, "end": { - "line": 19, + "line": 29, "column": 9 } }, @@ -362,22 +426,22 @@ }, { "type": "TSTypeAliasDeclaration", - "start": 482, - "end": 522, + "start": 486, + "end": 552, "loc": { "start": { "line": 15, "column": 1 }, "end": { - "line": 18, + "line": 20, "column": 6 } }, "id": { "type": "Identifier", - "start": 487, - "end": 490, + "start": 491, + "end": 508, "loc": { "start": { "line": 15, @@ -385,6 +449,272 @@ }, "end": { "line": 15, + "column": 23 + } + }, + "name": "FirstIntersection" + }, + "typeAnnotation": { + "type": "TSUnionType", + "start": 513, + "end": 551, + "loc": { + "start": { + "line": 16, + "column": 2 + }, + "end": { + "line": 20, + "column": 5 + } + }, + "types": [ + { + "type": "TSParenthesizedType", + "start": 515, + "end": 545, + "loc": { + "start": { + "line": 16, + "column": 4 + }, + "end": { + "line": 19, + "column": 5 + } + }, + "typeAnnotation": { + "type": "TSIntersectionType", + "start": 524, + "end": 544, + "loc": { + "start": { + "line": 17, + "column": 3 + }, + "end": { + "line": 19, + "column": 4 + } + }, + "types": [ + { + "type": "TSTypeReference", + "start": 524, + "end": 525, + "loc": { + "start": { + "line": 17, + "column": 3 + }, + "end": { + "line": 17, + "column": 4 + } + }, + "typeName": { + "type": "Identifier", + "start": 524, + "end": 525, + "loc": { + "start": { + "line": 17, + "column": 3 + }, + "end": { + "line": 17, + "column": 4 + } + }, + "name": "A" + } + }, + { + "type": "TSTypeLiteral", + "start": 528, + "end": 544, + "loc": { + "start": { + "line": 17, + "column": 7 + }, + "end": { + "line": 19, + "column": 4 + } + }, + "members": [ + { + "type": "TSPropertySignature", + "start": 534, + "end": 539, + "loc": { + "start": { + "line": 18, + "column": 4 + }, + "end": { + "line": 18, + "column": 9 + } + }, + "computed": false, + "key": { + "type": "Identifier", + "start": 534, + "end": 535, + "loc": { + "start": { + "line": 18, + "column": 4 + }, + "end": { + "line": 18, + "column": 5 + } + }, + "name": "a" + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start": 535, + "end": 538, + "loc": { + "start": { + "line": 18, + "column": 5 + }, + "end": { + "line": 18, + "column": 8 + } + }, + "typeAnnotation": { + "type": "TSLiteralType", + "start": 537, + "end": 538, + "loc": { + "start": { + "line": 18, + "column": 7 + }, + "end": { + "line": 18, + "column": 8 + } + }, + "literal": { + "type": "Literal", + "start": 537, + "end": 538, + "loc": { + "start": { + "line": 18, + "column": 7 + }, + "end": { + "line": 18, + "column": 8 + } + }, + "value": 1, + "raw": "1" + } + } + } + } + ] + } + ], + "leadingComments": [ + { + "type": "Line", + "value": " c", + "start": 516, + "end": 520 + } + ] + } + }, + { + "type": "TSTypeReference", + "start": 550, + "end": 551, + "loc": { + "start": { + "line": 20, + "column": 4 + }, + "end": { + "line": 20, + "column": 5 + } + }, + "typeName": { + "type": "Identifier", + "start": 550, + "end": 551, + "loc": { + "start": { + "line": 20, + "column": 4 + }, + "end": { + "line": 20, + "column": 5 + } + }, + "name": "C" + } + } + ] + }, + "leadingComments": [ + { + "type": "Line", + "value": " first member is a retained-paren intersection with a trailing object, which", + "start": 273, + "end": 351 + }, + { + "type": "Line", + "value": " supplies its own aligned layout - the comment is kept inside the parens the same", + "start": 353, + "end": 436 + }, + { + "type": "Line", + "value": " way, hugging the `(` above the intersection", + "start": 438, + "end": 484 + } + ] + }, + { + "type": "TSTypeAliasDeclaration", + "start": 764, + "end": 804, + "loc": { + "start": { + "line": 25, + "column": 1 + }, + "end": { + "line": 28, + "column": 6 + } + }, + "id": { + "type": "Identifier", + "start": 769, + "end": 772, + "loc": { + "start": { + "line": 25, + "column": 6 + }, + "end": { + "line": 25, "column": 9 } }, @@ -392,44 +722,44 @@ }, "typeAnnotation": { "type": "TSUnionType", - "start": 495, - "end": 521, + "start": 777, + "end": 803, "loc": { "start": { - "line": 16, + "line": 26, "column": 2 }, "end": { - "line": 18, + "line": 28, "column": 5 } }, "types": [ { "type": "TSTypeReference", - "start": 497, - "end": 498, + "start": 779, + "end": 780, "loc": { "start": { - "line": 16, + "line": 26, "column": 4 }, "end": { - "line": 16, + "line": 26, "column": 5 } }, "typeName": { "type": "Identifier", - "start": 497, - "end": 498, + "start": 779, + "end": 780, "loc": { "start": { - "line": 16, + "line": 26, "column": 4 }, "end": { - "line": 16, + "line": 26, "column": 5 } }, @@ -439,65 +769,65 @@ { "type": "Line", "value": " c", - "start": 499, - "end": 503 + "start": 781, + "end": 785 } ] }, { "type": "TSParenthesizedType", - "start": 508, - "end": 515, + "start": 790, + "end": 797, "loc": { "start": { - "line": 17, + "line": 27, "column": 4 }, "end": { - "line": 17, + "line": 27, "column": 11 } }, "typeAnnotation": { "type": "TSUnionType", - "start": 509, - "end": 514, + "start": 791, + "end": 796, "loc": { "start": { - "line": 17, + "line": 27, "column": 5 }, "end": { - "line": 17, + "line": 27, "column": 10 } }, "types": [ { "type": "TSTypeReference", - "start": 509, - "end": 510, + "start": 791, + "end": 792, "loc": { "start": { - "line": 17, + "line": 27, "column": 5 }, "end": { - "line": 17, + "line": 27, "column": 6 } }, "typeName": { "type": "Identifier", - "start": 509, - "end": 510, + "start": 791, + "end": 792, "loc": { "start": { - "line": 17, + "line": 27, "column": 5 }, "end": { - "line": 17, + "line": 27, "column": 6 } }, @@ -506,29 +836,29 @@ }, { "type": "TSTypeReference", - "start": 513, - "end": 514, + "start": 795, + "end": 796, "loc": { "start": { - "line": 17, + "line": 27, "column": 9 }, "end": { - "line": 17, + "line": 27, "column": 10 } }, "typeName": { "type": "Identifier", - "start": 513, - "end": 514, + "start": 795, + "end": 796, "loc": { "start": { - "line": 17, + "line": 27, "column": 9 }, "end": { - "line": 17, + "line": 27, "column": 10 } }, @@ -540,29 +870,29 @@ }, { "type": "TSTypeReference", - "start": 520, - "end": 521, + "start": 802, + "end": 803, "loc": { "start": { - "line": 18, + "line": 28, "column": 4 }, "end": { - "line": 18, + "line": 28, "column": 5 } }, "typeName": { "type": "Identifier", - "start": 520, - "end": 521, + "start": 802, + "end": 803, "loc": { "start": { - "line": 18, + "line": 28, "column": 4 }, "end": { - "line": 18, + "line": 28, "column": 5 } }, @@ -575,20 +905,20 @@ { "type": "Line", "value": " a leading line comment inside a LATER member's parens relocates to trail the", - "start": 273, - "end": 352 + "start": 555, + "end": 634 }, { "type": "Line", "value": " previous member; only the first member - with no previous member to relocate", - "start": 354, - "end": 433 + "start": 636, + "end": 715 }, { "type": "Line", "value": " onto - keeps the comment inside the parens", - "start": 435, - "end": 480 + "start": 717, + "end": 762 } ] } diff --git a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/input.svelte b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/input.svelte index 9a88c00ce..5237b0c36 100644 --- a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/input.svelte +++ b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/input.svelte @@ -9,6 +9,16 @@ ) | C; + // first member is a retained-paren intersection with a trailing object, which + // supplies its own aligned layout - the comment is kept inside the parens the same + // way, hugging the `(` above the intersection + type FirstIntersection = + | (// c + A & { + a: 1; + }) + | C; + // a leading line comment inside a LATER member's parens relocates to trail the // previous member; only the first member - with no previous member to relocate // onto - keeps the comment inside the parens diff --git a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/output_prettier.svelte b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/output_prettier.svelte index 09d82437e..58c90bd9e 100644 --- a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/output_prettier.svelte +++ b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/output_prettier.svelte @@ -7,6 +7,16 @@ (A | B) | C; + // first member is a retained-paren intersection with a trailing object, which + // supplies its own aligned layout - the comment is kept inside the parens the same + // way, hugging the `(` above the intersection + type FirstIntersection = + | // c + (A & { + a: 1; + }) + | C; + // a leading line comment inside a LATER member's parens relocates to trail the // previous member; only the first member - with no previous member to relocate // onto - keeps the comment inside the parens diff --git a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/unformatted_ours_inside_parens.svelte b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/unformatted_ours_inside_parens.svelte index 064cc2ac6..74be18065 100644 --- a/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/unformatted_ours_inside_parens.svelte +++ b/tests/fixtures/typescript/types/union_intersection_retained_paren_leading_line_comment_prettier_divergence/unformatted_ours_inside_parens.svelte @@ -7,6 +7,16 @@ A | B) | C; + // first member is a retained-paren intersection with a trailing object, which + // supplies its own aligned layout - the comment is kept inside the parens the same + // way, hugging the `(` above the intersection + type FirstIntersection = + | (// c + A & { + a: 1; + }) + | C; + // a leading line comment inside a LATER member's parens relocates to trail the // previous member; only the first member - with no previous member to relocate // onto - keeps the comment inside the parens