Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Print leading comment for readonly modifier of TS Mapped Types #11190

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 23 additions & 0 deletions changelog_unreleased/typescript/11190.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#### Print leading comment for readonly modifier of TS Mapped Types (#11190 by @sosukesuzuki)

<!-- prettier-ignore -->
```ts
// Input
type Type = {
// comment
readonly [key in Foo];
};

// Prettier stable
type Type = {
readonly // comment
[key in Foo];
};

// Prettier main
type Type = {
// comment
readonly [key in Foo];
};

```
73 changes: 73 additions & 0 deletions src/language-js/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const {
isCallExpression,
isMemberExpression,
isObjectProperty,
danglingCommentMarkerForReadonlyMappedType,
} = require("./utils");
const { locStart, locEnd } = require("./loc");

Expand Down Expand Up @@ -65,6 +66,7 @@ function handleOwnLineComment(context) {
handleAssignmentPatternComments,
handleMethodNameComments,
handleLabeledStatementComments,
handleOwnLineMappedTypesComments,
].some((fn) => fn(context));
}

Expand Down Expand Up @@ -331,6 +333,26 @@ function handleMemberExpressionComments({
return false;
}

/**
* @param {CommentContext} context
* @return {boolean}
*/
function handleOwnLineMappedTypesComments({ enclosingNode, comment, text }) {
if (
enclosingNode &&
enclosingNode.type === "TSMappedType" &&
isCommentBeforeMappedTypeReadonly(enclosingNode, text, comment)
) {
addDanglingComment(
enclosingNode,
comment,
danglingCommentMarkerForReadonlyMappedType
);
return true;
}
return false;
}

function handleConditionalExpressionComments({
comment,
precedingNode,
Expand Down Expand Up @@ -970,6 +992,57 @@ function willPrintOwnComments(path /*, options */) {
);
}

/**
* Checks if a comment is before `readonly` for Mapped Types.
* type Foo = {
* // comment
* readonly [key in Foo]: Bar;
* };
* @param {any} enclosingNode
* @param {CommentContext["text"]} text
* @param {CommentContext["comment"]} comment
* @returns {boolean}
*/
function isCommentBeforeMappedTypeReadonly(enclosingNode, text, comment) {
if (!enclosingNode.readonly) {
return false;
}
const nextIndexOfComment = getNextNonSpaceNonCommentCharacterIndex(
text,
comment,
locEnd
);
if (!nextIndexOfComment) {
return false;
}
const isReadonlyString =
enclosingNode.readonly === "+" || enclosingNode.readonly === "-";
const readonlyStartIndex = isReadonlyString
? getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
text,
nextIndexOfComment + 1
)
: nextIndexOfComment;
if (!readonlyStartIndex) {
return false;
}
const READONLY_KEYWORD = "readonly";
const readonlyEndIndex = readonlyStartIndex + READONLY_KEYWORD.length;
const maybeReadonlyString = text.slice(readonlyStartIndex, readonlyEndIndex);
if (maybeReadonlyString !== READONLY_KEYWORD) {
return false;
}
const afterReadonlyIndex =
getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
text,
readonlyEndIndex
);
if (!afterReadonlyIndex) {
return false;
}
return text[afterReadonlyIndex] === "[";
}

module.exports = {
handleOwnLineComment,
handleEndOfLineComment,
Expand Down
16 changes: 15 additions & 1 deletion src/language-js/print/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const {
shouldPrintComma,
isCallExpression,
isMemberExpression,
danglingCommentMarkerForReadonlyMappedType,
} = require("../utils");
const { locStart, locEnd } = require("../loc");

Expand Down Expand Up @@ -297,13 +298,21 @@ function printTypescript(path, options, print) {
locStart(node),
locEnd(node)
);
const printedLeadingCommentsForReadonly = printDanglingComments(
path,
options,
/* sameIndent */ true,
({ marker }) => marker === danglingCommentMarkerForReadonlyMappedType
);
return group(
[
"{",
indent([
options.bracketSpacing ? line : softline,
node.readonly
? [
printedLeadingCommentsForReadonly,
printedLeadingCommentsForReadonly && hardline,
getTypeScriptMappedTypeModifier(node.readonly, "readonly"),
" ",
]
Expand All @@ -317,7 +326,12 @@ function printTypescript(path, options, print) {
print("typeAnnotation"),
ifBreak(semi),
]),
printDanglingComments(path, options, /* sameIndent */ true),
printDanglingComments(
path,
options,
/* sameIndent */ true,
({ marker }) => !marker
),
options.bracketSpacing ? line : softline,
"}",
],
Expand Down
4 changes: 4 additions & 0 deletions src/language-js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,9 @@ function isObjectProperty(node) {
);
}

const danglingCommentMarkerForReadonlyMappedType =
"danglingCommentMarkerForReadonlyMappedType";

module.exports = {
getFunctionParameters,
iterateFunctionParametersPath,
Expand Down Expand Up @@ -1368,4 +1371,5 @@ module.exports = {
hasComment,
getComments,
CommentCheckFlags,
danglingCommentMarkerForReadonlyMappedType,
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,97 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`issue-11098.ts format 1`] = `
====================================options=====================================
parsers: ["typescript"]
printWidth: 80
| printWidth
=====================================input======================================
type Type = {
// comment
readonly [T in number];
};

type Type = {
// comment1
// comment2
readonly [T in number];
};

type Type = {
// comment
+readonly [T in number];
};

type Type = {
// comment
-readonly [T in number];
};

type Type = {
// comment
+ readonly [T in number];
};

type Type = {
// comment
+readonly [T in number];
};

type Type = {
// comment
readonly [T in number];
};

type Type = {
// comment
[T in number];
};

=====================================output=====================================
type Type = {
// comment
readonly [T in number];
};

type Type = {
// comment1
// comment2
readonly [T in number];
};

type Type = {
// comment
+readonly [T in number];
};

type Type = {
// comment
-readonly [T in number];
};

type Type = {
// comment
+readonly [T in number];
};

type Type = {
// comment
+readonly [T in number];
};

type Type = {
// comment
readonly [T in number];
};

type Type = {
// comment
[T in number];
};

================================================================================
`;

exports[`mapped-type.ts format 1`] = `
====================================options=====================================
parsers: ["typescript"]
Expand Down
40 changes: 40 additions & 0 deletions tests/format/typescript/mapped-type/issue-11098.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
type Type = {
// comment
readonly [T in number];
};

type Type = {
// comment1
// comment2
readonly [T in number];
};

type Type = {
// comment
+readonly [T in number];
};

type Type = {
// comment
-readonly [T in number];
};

type Type = {
// comment
+ readonly [T in number];
};

type Type = {
// comment
+readonly [T in number];
};

type Type = {
// comment
readonly [T in number];
};

type Type = {
// comment
[T in number];
};