From e9ae01a6da550517fd60cf257476c9e1d705708e Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Fri, 10 Feb 2023 14:23:42 +0800 Subject: [PATCH] Update `prettier.util.{isPreviousLineEmpty,isNextLineEmpty}` (#14320) --- changelog_unreleased/api/14317.md | 42 ++++++++++++++- docs/plugins.md | 14 +---- src/common/util-shared.js | 62 ++++++++++++++++++++-- src/common/util.js | 27 +++------- src/language-css/printer-postcss.js | 4 +- src/language-graphql/printer-graphql.js | 2 +- src/language-js/print/member-chain.js | 2 +- src/language-js/utils/index.js | 2 +- src/language-yaml/printer-yaml.js | 2 +- src/main/comments.js | 3 +- tests/integration/__tests__/util-shared.js | 45 ++++++++++++++++ 11 files changed, 160 insertions(+), 45 deletions(-) diff --git a/changelog_unreleased/api/14317.md b/changelog_unreleased/api/14317.md index 9367d8448..2d714e0b8 100644 --- a/changelog_unreleased/api/14317.md +++ b/changelog_unreleased/api/14317.md @@ -1,4 +1,4 @@ -#### Update `prettier.util` (#14317 by @fisker) +#### Update `prettier.util` (#14317, #14320 by @fisker) - Added `prettier.util.getNextNonSpaceNonCommentCharacter` - Changed `prettier.util.getNextNonSpaceNonCommentCharacter` @@ -22,4 +22,44 @@ ): number | false; ``` +- Changed `prettier.util.isPreviousLineEmpty` + + Signature changed from + + ```ts + function isPreviousLineEmpty( + text: string, + node: N, + locStart: (node: N) => number + ): boolean; + ``` + + to + + ```ts + function isPreviousLineEmpty(text: string, startIndex: number): boolean; + ``` + +- Changed `prettier.util.isNextLineEmpty` + + Signature changed from + + ```ts + function isNextLineEmpty( + text: string, + node: N, + locEnd: (node: N) => number + ): boolean; + ``` + + to + + ```ts + function isNextLineEmpty(text: string, startIndex: number): boolean; + ``` + +- Deprecated `prettier.util.isNextLineEmptyAfterIndex` + + Use `prettier.util.isNextLineEmpty` instead. + See the [documentation](https://prettier.io/docs/en/plugins.html#utility-functions) for details. diff --git a/docs/plugins.md b/docs/plugins.md index 7293d5ac7..b7ff51ea2 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -595,19 +595,9 @@ function getNextNonSpaceNonCommentCharacterIndex( startIndex: number ): number | false; -function isNextLineEmptyAfterIndex(text: string, index: number): boolean; +function isNextLineEmpty(text: string, startIndex: number): boolean; -function isNextLineEmpty( - text: string, - node: N, - locEnd: (node: N) => number -): boolean; - -function isPreviousLineEmpty( - text: string, - node: N, - locStart: (node: N) => number -): boolean; +function isPreviousLineEmpty(text: string, startIndex: number): boolean; ``` ### Tutorials diff --git a/src/common/util-shared.js b/src/common/util-shared.js index 1db41c586..441ea41e7 100644 --- a/src/common/util-shared.js +++ b/src/common/util-shared.js @@ -1,4 +1,8 @@ -import { getNextNonSpaceNonCommentCharacterIndex as getNextNonSpaceNonCommentCharacterIndexWithStartIndex } from "./util.js"; +import { + getNextNonSpaceNonCommentCharacterIndex as getNextNonSpaceNonCommentCharacterIndexWithStartIndex, + isPreviousLineEmpty as isPreviousLineEmptyWithStartIndex, + isNextLineEmpty as isNextLineEmptyAfterIndex, +} from "./util.js"; // Legacy version of `getNextNonSpaceNonCommentCharacterIndex` /** @@ -29,6 +33,57 @@ export function getNextNonSpaceNonCommentCharacterIndex(text, startIndex) { legacyGetNextNonSpaceNonCommentCharacterIndex(...arguments); } +// Legacy version of `isPreviousLineEmpty` +/** + * @template N + * @param {string} text + * @param {N} node + * @param {(node: N) => number} locStart + */ +function legacyIsPreviousLineEmpty(text, node, locStart) { + return isPreviousLineEmptyWithStartIndex(text, locStart(node)); +} + +// TODO: export `isPreviousLineEmpty` directly in v4 +/** + * @param {string} text + * @param {number} startIndex + * @returns {boolean} + */ +export function isPreviousLineEmpty(text, startIndex) { + return arguments.length === 2 || typeof startIndex === "number" + ? isPreviousLineEmptyWithStartIndex(text, startIndex) + : // @ts-expect-error -- expected + // eslint-disable-next-line prefer-rest-params + legacyIsPreviousLineEmpty(...arguments); +} + +// Legacy version of `isNextLineEmpty` +/** + * @template N + * @param {string} text + * @param {N} node + * @param {(node: N) => number} locEnd + * @returns {boolean} + */ +function legacyIsNextLineEmpty(text, node, locEnd) { + return isNextLineEmptyAfterIndex(text, locEnd(node)); +} + +// TODO: export `isNextLineEmpty` directly in v4 +/** + * @param {string} text + * @param {number} startIndex + * @returns {boolean} + */ +export function isNextLineEmpty(text, startIndex) { + return arguments.length === 2 || typeof startIndex === "number" + ? isNextLineEmptyAfterIndex(text, startIndex) + : // @ts-expect-error -- expected + // eslint-disable-next-line prefer-rest-params + legacyIsNextLineEmpty(...arguments); +} + export { getMaxContinuousCount, getStringWidth, @@ -45,12 +100,11 @@ export { hasNewline, hasNewlineInRange, hasSpaces, - isNextLineEmpty, - isNextLineEmptyAfterIndex, - isPreviousLineEmpty, getNextNonSpaceNonCommentCharacter, makeString, addLeadingComment, addDanglingComment, addTrailingComment, + // Remove this in v4 + isNextLineEmpty as isNextLineEmptyAfterIndex, } from "./util.js"; diff --git a/src/common/util.js b/src/common/util.js index 377c75cb2..4ed83c0c9 100644 --- a/src/common/util.js +++ b/src/common/util.js @@ -44,14 +44,13 @@ function hasNewlineInRange(text, start, end) { // Note: this function doesn't ignore leading comments unlike isNextLineEmpty /** - * @template N * @param {string} text - * @param {N} node - * @param {(node: N) => number} locStart + * @param {number} startIndex + * @returns {boolean} */ -function isPreviousLineEmpty(text, node, locStart) { +function isPreviousLineEmpty(text, startIndex) { /** @type {number | false} */ - let idx = locStart(node) - 1; + let idx = startIndex - 1; idx = skipSpaces(text, idx, { backwards: true }); idx = skipNewline(text, idx, { backwards: true }); idx = skipSpaces(text, idx, { backwards: true }); @@ -61,14 +60,14 @@ function isPreviousLineEmpty(text, node, locStart) { /** * @param {string} text - * @param {number} index + * @param {number} startIndex * @returns {boolean} */ -function isNextLineEmptyAfterIndex(text, index) { +function isNextLineEmpty(text, startIndex) { /** @type {number | false} */ let oldIdx = null; /** @type {number | false} */ - let idx = index; + let idx = startIndex; while (idx !== oldIdx) { // We need to skip all the potential trailing inline comments oldIdx = idx; @@ -81,17 +80,6 @@ function isNextLineEmptyAfterIndex(text, index) { return idx !== false && hasNewline(text, idx); } -/** - * @template N - * @param {string} text - * @param {N} node - * @param {(node: N) => number} locEnd - * @returns {boolean} - */ -function isNextLineEmpty(text, node, locEnd) { - return isNextLineEmptyAfterIndex(text, locEnd(node)); -} - /** * @param {string} text * @param {number} startIndex @@ -414,7 +402,6 @@ export { skipInlineComment, skipTrailingComment, skipNewline, - isNextLineEmptyAfterIndex, isNextLineEmpty, isPreviousLineEmpty, hasNewline, diff --git a/src/language-css/printer-postcss.js b/src/language-css/printer-postcss.js index 6d2c3a686..b57e4d1ed 100644 --- a/src/language-css/printer-postcss.js +++ b/src/language-css/printer-postcss.js @@ -989,7 +989,7 @@ function genericPrint(path, options, print) { if ( last.source && - isNextLineEmpty(options.originalText, last, locEnd) + isNextLineEmpty(options.originalText, locEnd(last)) ) { printed.push(hardline); } @@ -1109,7 +1109,7 @@ function printNodeSequence(path, options, print) { } else { parts.push(options.__isHTMLStyleAttribute ? line : hardline); if ( - isNextLineEmpty(options.originalText, node, locEnd) && + isNextLineEmpty(options.originalText, locEnd(node)) && !isFrontMatterNode(node) ) { parts.push(hardline); diff --git a/src/language-graphql/printer-graphql.js b/src/language-graphql/printer-graphql.js index b8c144364..32d638127 100644 --- a/src/language-graphql/printer-graphql.js +++ b/src/language-graphql/printer-graphql.js @@ -434,7 +434,7 @@ function printSequence(path, options, print, property) { return path.map(({ isLast, node }) => { const printed = print(); - if (!isLast && isNextLineEmpty(options.originalText, node, locEnd)) { + if (!isLast && isNextLineEmpty(options.originalText, locEnd(node))) { return [printed, hardline]; } diff --git a/src/language-js/print/member-chain.js b/src/language-js/print/member-chain.js index d369af056..77d277a93 100644 --- a/src/language-js/print/member-chain.js +++ b/src/language-js/print/member-chain.js @@ -1,6 +1,6 @@ import { printComments } from "../../main/comments.js"; import { - isNextLineEmptyAfterIndex, + isNextLineEmpty as isNextLineEmptyAfterIndex, getNextNonSpaceNonCommentCharacterIndex, } from "../../common/util.js"; import pathNeedsParens from "../needs-parens.js"; diff --git a/src/language-js/utils/index.js b/src/language-js/utils/index.js index ba8c95752..598cd25ec 100644 --- a/src/language-js/utils/index.js +++ b/src/language-js/utils/index.js @@ -2,7 +2,7 @@ import isEs5IdentifierName from "@prettier/is-es5-identifier-name"; import { hasNewline, isNonEmptyArray, - isNextLineEmptyAfterIndex, + isNextLineEmpty as isNextLineEmptyAfterIndex, getStringWidth, } from "../../common/util.js"; import { locStart, locEnd, hasSameLocStart } from "../loc.js"; diff --git a/src/language-yaml/printer-yaml.js b/src/language-yaml/printer-yaml.js index 07871ef75..a721d11f5 100644 --- a/src/language-yaml/printer-yaml.js +++ b/src/language-yaml/printer-yaml.js @@ -129,7 +129,7 @@ function genericPrint(path, options, print) { hardline, path.map( ({ node }) => [ - isPreviousLineEmpty(options.originalText, node, locStart) + isPreviousLineEmpty(options.originalText, locStart(node)) ? hardline : "", print(), diff --git a/src/main/comments.js b/src/main/comments.js index 646449364..6620e8aa3 100644 --- a/src/main/comments.js +++ b/src/main/comments.js @@ -487,8 +487,7 @@ function printTrailingComment(path, options, previousComment) { const isLineBeforeEmpty = isPreviousLineEmpty( originalText, - comment, - locStart + locStart(comment) ); return { diff --git a/tests/integration/__tests__/util-shared.js b/tests/integration/__tests__/util-shared.js index a88f8209b..eaec94a3f 100644 --- a/tests/integration/__tests__/util-shared.js +++ b/tests/integration/__tests__/util-shared.js @@ -151,6 +151,51 @@ test("sharedUtil.getNextNonSpaceNonCommentCharacter and sharedUtil.getNextNonSpa } }); +test("sharedUtil.isPreviousLineEmpty, sharedUtil.isNextLineEmpty and sharedUtil.isNextLineEmptyAfterIndex", () => { + const { isPreviousLineEmpty, isNextLineEmpty, isNextLineEmptyAfterIndex } = + sharedUtil; + const FAKE_NODE_A = { type: "Identifier", name: "a" }; + const FAKE_NODE_B = { type: "Identifier", name: "b" }; + + { + const text = "a\n \t \t \nb"; + const endOfIdentifierA = text.indexOf("a") + 1; + const startOfIdentifierB = text.indexOf("b"); + + expect(isPreviousLineEmpty(text, startOfIdentifierB)).toBe(true); + expect( + isPreviousLineEmpty(text, FAKE_NODE_B, () => startOfIdentifierB) + ).toBe(true); + expect(isNextLineEmpty(text, endOfIdentifierA)).toBe(true); + expect(isNextLineEmptyAfterIndex(text, endOfIdentifierA)).toBe(true); + expect(isNextLineEmpty(text, FAKE_NODE_A, () => endOfIdentifierA)).toBe( + true + ); + } + + { + const text = "a\n \t NON_SPACE \t \nb"; + const endOfIdentifierA = text.indexOf("a") + 1; + const startOfIdentifierB = text.indexOf("b"); + + expect(isPreviousLineEmpty(text, startOfIdentifierB)).toBe(false); + expect( + isPreviousLineEmpty(text, FAKE_NODE_B, () => startOfIdentifierB) + ).toBe(false); + expect(isNextLineEmpty(text, endOfIdentifierA)).toBe(false); + expect(isNextLineEmptyAfterIndex(text, endOfIdentifierA)).toBe(false); + expect(isNextLineEmpty(text, FAKE_NODE_A, () => endOfIdentifierA)).toBe( + false + ); + } + + let called = false; + isNextLineEmptyAfterIndex("text", {}, () => { + called = true; + }); + expect(called).toBe(false); +}); + test("sharedUtil.makeString", () => { const { makeString } = sharedUtil; const DOUBLE_QUOTE = '"';