diff --git a/changelog_unreleased/api/18055.md b/changelog_unreleased/api/18055.md index e27253e8d..8b7f949c6 100644 --- a/changelog_unreleased/api/18055.md +++ b/changelog_unreleased/api/18055.md @@ -1,4 +1,4 @@ -#### Pass ancestors to `plugin.print.canAttachComment()` (#18055 by @fisker) +#### Pass ancestors to `plugin.printer.canAttachComment()` (#18055 by @fisker) This prevent attaching comments to a specific child of node. diff --git a/changelog_unreleased/api/18070.md b/changelog_unreleased/api/18070.md new file mode 100644 index 000000000..8d04ebd39 --- /dev/null +++ b/changelog_unreleased/api/18070.md @@ -0,0 +1,5 @@ +#### Add support for `plugin.printer.printPrettierIgnored()` (#18070 by @fisker) + +For a node with `prettier-ignore` comment, Prettier prints the text of the node directly. However, this may cause problems, for example, the node needs to be parenthesized or needs to print a leading semicolon to prevent ASI issue in `--no-semi` mode. + +Since Prettier main, plugins can add `printPrettierIgnored()` function to the printer to customize the `prettier-ignore`d node print process. This function uses the extract same signature as [`plugin.printer.print()`](https://prettier.io/docs/plugins#print) diff --git a/docs/plugins.md b/docs/plugins.md index 8d7718f34..fa5cfbba1 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -152,6 +152,8 @@ _(Optional)_ The preprocess function can process the input text before passing i function preprocess(text: string, options: object): string | Promise; ``` +_Support for async preprocess first added in v3.7.0_ + ### `printers` Printers convert ASTs into a Prettier intermediate representation, also known as a Doc. @@ -170,6 +172,8 @@ export const printers = { isBlockComment, printComment, getCommentChildNodes, + hasPrettierIgnore, + printPrettierIgnored, handleComments: { ownLine, endOfLine, @@ -394,6 +398,22 @@ function getCommentChildNodes( Return `[]` if the node has no children or `undefined` to fall back on the default behavior. +### (optional) `hasPrettierIgnore` + +```ts +function hasPrettierIgnore(path: AstPath): boolean; +``` + +Returns whether or not the AST node is `prettier-ignore`d. + +### (optional) `printPrettierIgnored` + +If the AST node is `prettier-ignore`d, Prettier will slice for the text for parsing without calling `print` function by default, however plugin can also handle the `prettier-ignore`d node print by adding this property. + +This property have the same signature as the `print` property. + +_First available in v3.7.0_ + #### (optional) `printComment` Called whenever a comment node needs to be printed. It has the signature: @@ -413,12 +433,6 @@ function printComment( function canAttachComment(node: AST, ancestors: T[]): boolean; ``` -:::note - -The second parameter `ancestors` first added in v3.7.0. - -::: - This function is used for deciding whether a comment can be attached to a particular AST node. By default, _all_ AST properties are traversed searching for nodes that comments can be attached to. This function is used to prevent comments from being attached to a particular node. A typical implementation looks like ```js @@ -432,6 +446,8 @@ function canAttachComment(node, [parent]) { } ``` +_The second parameter `ancestors` first added in v3.7.0._ + #### (optional) `isBlockComment` ```ts diff --git a/src/index.d.ts b/src/index.d.ts index cd177ff8b..6f8b6a9fe 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -491,6 +491,12 @@ export interface Printer { print: (path: AstPath) => Doc, args?: unknown, ): Doc; + printPrettierIgnored?( + path: AstPath, + options: ParserOptions, + print: (path: AstPath) => Doc, + args?: unknown, + ): Doc; embed?: | (( path: AstPath, diff --git a/src/language-js/print/index.js b/src/language-js/print/index.js index 1db75c1d1..fb8b097f6 100644 --- a/src/language-js/print/index.js +++ b/src/language-js/print/index.js @@ -1,7 +1,7 @@ import { group, indent, line } from "../../document/builders.js"; import { inheritLabel } from "../../document/utils.js"; -import printIgnored from "../../main/print-ignored.js"; import isNonEmptyArray from "../../utils/is-non-empty-array.js"; +import { locEnd, locStart } from "../loc.js"; import pathNeedsParens from "../needs-parens.js"; import { createTypeCheckFunction } from "../utils/index.js"; import isIgnored from "../utils/is-ignored.js"; @@ -19,10 +19,6 @@ import { printTypescript } from "./typescript.js"; */ function printWithoutParentheses(path, options, print, args) { - if (isIgnored(path)) { - return printIgnored(path, options); - } - for (const printer of [ printAngular, printJsx, @@ -65,12 +61,15 @@ function print(path, options, print, args) { options.__onHtmlBindingRoot?.(path.node, options); } - const doc = printWithoutParentheses(path, options, print, args); + const { node } = path; + + const doc = isIgnored(path) + ? options.originalText.slice(locStart(node), locEnd(node)) + : printWithoutParentheses(path, options, print, args); if (!doc) { return ""; } - const { node } = path; if (shouldPrintDirectly(node)) { return doc; } diff --git a/src/language-js/printer.js b/src/language-js/printer.js index 117fedb92..489de3a53 100644 --- a/src/language-js/printer.js +++ b/src/language-js/printer.js @@ -13,5 +13,9 @@ export { } from "./comments/printer-methods.js"; export { default as embed } from "./embed/index.js"; export { insertPragma } from "./pragma.js"; -export { default as print } from "./print/index.js"; +export { + default as print, + default as printPrettierIgnored, +} from "./print/index.js"; export { default as getVisitorKeys } from "./traverse/get-visitor-keys.js"; +export { default as hasPrettierIgnore } from "./utils/is-ignored.js"; diff --git a/src/main/ast-to-doc.js b/src/main/ast-to-doc.js index 27fd96d51..98590efeb 100644 --- a/src/main/ast-to-doc.js +++ b/src/main/ast-to-doc.js @@ -108,7 +108,7 @@ function callPluginPrintFunction(path, options, printPath, args, embeds) { // Escape hatch if (printer.hasPrettierIgnore?.(path)) { - doc = printIgnored(path, options); + doc = printIgnored(path, options, printPath, args); } else if (embeds.has(node)) { doc = embeds.get(node); } else { diff --git a/src/main/print-ignored.js b/src/main/print-ignored.js index 0af80290d..27d8fcb1d 100644 --- a/src/main/print-ignored.js +++ b/src/main/print-ignored.js @@ -1,4 +1,4 @@ -function printIgnored(path, options) { +function printIgnored(path, options, printPath, args) { const { originalText, [Symbol.for("comments")]: comments, @@ -17,7 +17,11 @@ function printIgnored(path, options) { } } - return originalText.slice(start, end); + const { printPrettierIgnored } = options.printer; + + return printPrettierIgnored + ? printPrettierIgnored(path, options, printPath, args) + : originalText.slice(start, end); } export default printIgnored;