Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions crates/oxc_formatter/src/write/mapped_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use oxc_ast::ast::{TSMappedType, TSMappedTypeModifierOperator};

use crate::{
FormatResult,
formatter::{Formatter, SourceText, prelude::*, trivia::FormatLeadingComments},
generated::ast_nodes::AstNode,
write,
write::semicolon::OptionalSemicolon,
};

use super::FormatWrite;

impl<'a> FormatWrite<'a> for AstNode<'a, TSMappedType<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
let type_parameter = self.type_parameter();
let name_type = self.name_type();
let should_expand = has_line_break_before_property_name(self, f.source_text());

let type_annotation_has_leading_comment =
f.comments().has_comment_before(type_parameter.span.start);

let format_inner = format_with(|f| {
if should_expand {
let comments =
f.context().comments().comments_before_character(self.span.start, b'[');
write!(f, FormatLeadingComments::Comments(comments))?;
}

if let Some(readonly) = self.readonly() {
let prefix = match readonly {
TSMappedTypeModifierOperator::True => "",
TSMappedTypeModifierOperator::Plus => "+",
TSMappedTypeModifierOperator::Minus => "-",
};
write!(f, [prefix, "readonly", space()])?;
}

let format_inner_inner = format_with(|f| {
write!(f, "[")?;
write!(f, type_parameter.name())?;
if let Some(constraint) = &type_parameter.constraint() {
write!(f, [space(), "in", space(), constraint])?;
}
if let Some(default) = &type_parameter.default() {
write!(f, [space(), "=", space(), default])?;
}
if let Some(name_type) = &name_type {
write!(f, [space(), "as", space(), name_type])?;
}
write!(f, "]")?;
if let Some(optional) = self.optional() {
write!(
f,
match optional {
TSMappedTypeModifierOperator::True => "?",
TSMappedTypeModifierOperator::Plus => "+?",
TSMappedTypeModifierOperator::Minus => "-?",
}
)?;
}
Ok(())
});

write!(f, [space(), group(&format_inner_inner)])?;
if let Some(type_annotation) = &self.type_annotation() {
write!(f, [":", space(), type_annotation])?;
}
write!(f, if_group_breaks(&OptionalSemicolon))
});

let should_insert_space_around_brackets = f.options().bracket_spacing.value();
write!(
f,
[
"{",
group(&soft_block_indent_with_maybe_space(
&format_inner,
should_insert_space_around_brackets
))
.should_expand(should_expand),
"}",
]
)
}
}

/// Check if the user introduced a new line inside the node, but only if
/// that new line occurs at or before the property name. For example,
/// this would break:
/// { [
/// A in B]: T}
/// Because the line break occurs before `A`, the property name. But this
/// would _not_ break:
/// { [A
/// in B]: T}
/// Because the break is _after_ the `A`.
fn has_line_break_before_property_name(node: &TSMappedType, f: SourceText) -> bool {
f.contains_newline_between(node.span.start, node.type_parameter.span.start)
}
70 changes: 1 addition & 69 deletions crates/oxc_formatter/src/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod import_declaration;
mod import_expression;
mod intersection_type;
mod jsx;
mod mapped_type;
mod member_expression;
mod object_like;
mod object_pattern_like;
Expand Down Expand Up @@ -1828,75 +1829,6 @@ impl<'a> FormatWrite<'a> for AstNode<'a, TSConstructorType<'a>> {
}
}

impl<'a> FormatWrite<'a> for AstNode<'a, TSMappedType<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
let type_parameter = self.type_parameter();
let name_type = self.name_type();

let should_expand = false; // TODO has_line_break_before_property_name(node)?;

let type_annotation_has_leading_comment = false;
//TODO
//
// mapped_type
// .as_ref()
// .is_some_and(|annotation| comments.has_leading_comments(annotation.syntax()));

let format_inner = format_with(|f| {
// TODO:
// write!(f, FormatLeadingComments::Comments(comments.dangling_comments(self.span())))?;

match self.readonly() {
Some(TSMappedTypeModifierOperator::True) => write!(f, ["readonly", space()])?,
Some(TSMappedTypeModifierOperator::Plus) => write!(f, ["+readonly", space()])?,
Some(TSMappedTypeModifierOperator::Minus) => write!(f, ["-readonly", space()])?,
None => {}
}

let format_inner_inner = format_with(|f| {
write!(f, "[")?;
write!(f, type_parameter.name())?;
if let Some(constraint) = &type_parameter.constraint() {
write!(f, [space(), "in", space(), constraint])?;
}
if let Some(default) = &type_parameter.default() {
write!(f, [space(), "=", space(), default])?;
}
if let Some(name_type) = &name_type {
write!(f, [space(), "as", space(), name_type])?;
}
write!(f, "]")?;
match self.optional() {
Some(TSMappedTypeModifierOperator::True) => write!(f, "?"),
Some(TSMappedTypeModifierOperator::Plus) => write!(f, "+?"),
Some(TSMappedTypeModifierOperator::Minus) => write!(f, "-?"),
None => Ok(()),
}
});

write!(f, [space(), group(&format_inner_inner)])?;
if let Some(type_annotation) = &self.type_annotation() {
write!(f, [":", space(), type_annotation])?;
}
write!(f, if_group_breaks(&OptionalSemicolon))
});

let should_insert_space_around_brackets = f.options().bracket_spacing.value();
write!(
f,
[
"{",
group(&soft_block_indent_with_maybe_space(
&format_inner,
should_insert_space_around_brackets
))
.should_expand(should_expand),
"}",
]
)
}
}

impl<'a> FormatWrite<'a> for AstNode<'a, TSTypeAssertion<'a>> {
fn write(&self, f: &mut Formatter<'_, 'a>) -> FormatResult<()> {
let break_after_cast = !matches!(
Expand Down
14 changes: 3 additions & 11 deletions tasks/prettier_conformance/snapshots/prettier.ts.snap.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ts compatibility: 487/573 (84.99%)
ts compatibility: 495/573 (86.39%)

# Failed

Expand Down Expand Up @@ -27,7 +27,6 @@ ts compatibility: 487/573 (84.99%)
| typescript/comments/16207.ts | 💥 | 71.43% |
| typescript/comments/16889.ts | 💥 | 62.61% |
| typescript/comments/location.ts | 💥 | 95.00% |
| typescript/comments/mapped_types.ts | 💥 | 58.82% |
| typescript/comments/method_types.ts | 💥 | 79.49% |
| typescript/comments/type-parameters.ts | 💥 | 65.52% |
| typescript/comments/type_literals.ts | 💥 | 68.97% |
Expand All @@ -38,14 +37,11 @@ ts compatibility: 487/573 (84.99%)
| typescript/conditional-types/conditonal-types.ts | 💥✨ | 34.48% |
| typescript/conditional-types/infer-type.ts | 💥✨ | 4.76% |
| typescript/conditional-types/nested-in-condition.ts | 💥✨ | 15.79% |
| typescript/conditional-types/new-ternary-spec.ts | 💥💥 | 58.18% |
| typescript/conditional-types/new-ternary-spec.ts | 💥 | 10.67% |
| typescript/conditional-types/parentheses.ts | 💥✨ | 15.22% |
| typescript/conformance/types/functions/functionOverloadErrorsSyntax.ts | 💥 | 0.00% |
| typescript/conformance/types/namespaceExportDeclaration/exportAsNamespace.d.ts | 💥 | 75.00% |
| typescript/custom/computedProperties/string.ts | 💥 | 73.33% |
| typescript/custom/modifiers/minustoken.ts | 💥 | 20.00% |
| typescript/custom/modifiers/question.ts | 💥 | 0.00% |
| typescript/custom/modifiers/readonly.ts | 💥 | 0.00% |
| typescript/declare/object-type-in-declare-function.ts | 💥 | 56.25% |
| typescript/decorators/comments.ts | 💥 | 60.00% |
| typescript/decorators/decorators-comments.ts | 💥 | 65.71% |
Expand All @@ -63,17 +59,13 @@ ts compatibility: 487/573 (84.99%)
| typescript/interface2/comments.ts | 💥 | 78.87% |
| typescript/intersection/intersection-parens.ts | 💥💥 | 72.25% |
| typescript/intersection/consistent-with-flow/intersection-parens.ts | 💥 | 69.77% |
| typescript/key-remapping-in-mapped-types/key-remapping.ts | 💥 | 55.56% |
| typescript/last-argument-expansion/decorated-function.tsx | 💥 | 29.06% |
| typescript/mapped-type/intersection.ts | 💥 | 0.00% |
| typescript/mapped-type/issue-11098.ts | 💥 | 60.00% |
| typescript/mapped-type/break-mode/break-mode.ts | 💥 | 40.00% |
| typescript/method/issue-10352-consistency.ts | 💥 | 63.64% |
| typescript/module/global.ts | 💥 | 75.00% |
| typescript/multiparser-css/issue-6259.ts | 💥 | 57.14% |
| typescript/non-null/optional-chain.ts | 💥 | 72.22% |
| typescript/object-multiline/multiline.ts | 💥✨ | 23.21% |
| typescript/prettier-ignore/mapped-types.ts | 💥 | 54.72% |
| typescript/prettier-ignore/mapped-types.ts | 💥 | 63.16% |
| typescript/prettier-ignore/prettier-ignore-nested-unions.ts | 💥 | 29.17% |
| typescript/prettier-ignore/prettier-ignore-parenthesized-type.ts | 💥 | 0.00% |
| typescript/satisfies-operators/expression-statement.ts | 💥💥 | 78.38% |
Expand Down
Loading