diff --git a/changelog_unreleased/api/16567.md b/changelog_unreleased/api/16567.md new file mode 100644 index 000000000..8147d50c0 --- /dev/null +++ b/changelog_unreleased/api/16567.md @@ -0,0 +1,34 @@ +#### Make `getPreferredQuote` public (#16567 by @sosukesuzuki) + +This change makes the internal `getPreferredQuote` function a part of the public API. + +In languages like JavaScript, both single quotes and double quotes can be used for string literals. Prettier determines the quote to enclose a string literal based on the number of quotes within the string and the value of the [`singleQuote`](https://prettier.io/docs/en/options#quotes) option. For more details, please refer to the [Rationale](https://prettier.io/docs/en/rationale.html#strings) page. + +The `getPreferredQuote` function determines the appropriate quote to enclose a string literal and has the following interface: + +```ts +type Quote = '"' | "'"; +function getPreferredQuote( + text: string, + preferredQuoteOrPreferSingleQuote: Quote | boolean, +): Quote; +``` + +Here are some examples of how to use it: + + +```jsx +import * as prettier from "prettier"; + +const SINGLE_QUOTE = `'`; +const DOUBLE_QUOTE = `"`; + +console.log(prettier.util.getPreferredQuote(`Hello World Test`, SINGLE_QUOTE)); // ' +console.log(prettier.util.getPreferredQuote(`Hello World Test`, DOUBLE_QUOTE)); // " +console.log(prettier.util.getPreferredQuote(`'Hello' "World" 'Test'`, SINGLE_QUOTE)); // " +console.log(prettier.util.getPreferredQuote(`"Hello" 'World' "Test"`, DOUBLE_QUOTE)); // ' +console.log(prettier.util.getPreferredQuote(`"Hello" "World" "Test"`, SINGLE_QUOTE)); // ' +console.log(prettier.util.getPreferredQuote(`'Hello' 'World' 'Test'`, DOUBLE_QUOTE)); // " +``` + +Making this function public will benefit plugin developers. Since the function is relatively short, you can find more details in the [implementation](https://github.com/prettier/prettier/blob/509a0cc10f12cbfa5304737965f99284449aca88/src/utils/get-preferred-quote.js). diff --git a/docs/plugins.md b/docs/plugins.md index bfa039eab..9bd503f83 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -609,6 +609,11 @@ function getNextNonSpaceNonCommentCharacterIndex( function isNextLineEmpty(text: string, startIndex: number): boolean; function isPreviousLineEmpty(text: string, startIndex: number): boolean; + +function getPreferredQuote( + text: string, + preferredQuoteOrPreferSingleQuote: Quote | boolean, +): Quote; ``` ### Tutorials diff --git a/src/index.d.ts b/src/index.d.ts index c4b6e29d0..8e4df1647 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -938,4 +938,9 @@ export namespace util { function addDanglingComment(node: any, comment: any, marker: any): void; function addTrailingComment(node: any, comment: any): void; + + function getPreferredQuote( + text: string, + preferredQuoteOrPreferSingleQuote: Quote | boolean, + ): Quote; } diff --git a/src/utils/get-preferred-quote.js b/src/utils/get-preferred-quote.js index 720095eb3..ec1a85ff7 100644 --- a/src/utils/get-preferred-quote.js +++ b/src/utils/get-preferred-quote.js @@ -7,11 +7,11 @@ const DOUBLE_QUOTE = '"'; /** * - * @param {string} rawContent + * @param {string} text * @param {Quote | boolean} preferredQuoteOrPreferSingleQuote * @returns {Quote} */ -function getPreferredQuote(rawContent, preferredQuoteOrPreferSingleQuote) { +function getPreferredQuote(text, preferredQuoteOrPreferSingleQuote) { const preferred = preferredQuoteOrPreferSingleQuote === true || preferredQuoteOrPreferSingleQuote === SINGLE_QUOTE @@ -21,7 +21,7 @@ function getPreferredQuote(rawContent, preferredQuoteOrPreferSingleQuote) { let preferredQuoteCount = 0; let alternateQuoteCount = 0; - for (const character of rawContent) { + for (const character of text) { if (character === preferred) { preferredQuoteCount++; } else if (character === alternate) { diff --git a/src/utils/public.js b/src/utils/public.js index 9bf12ace3..44ae192dc 100644 --- a/src/utils/public.js +++ b/src/utils/public.js @@ -91,6 +91,7 @@ export { default as getAlignmentSize } from "./get-alignment-size.js"; export { default as getIndentSize } from "./get-indent-size.js"; export { default as getMaxContinuousCount } from "./get-max-continuous-count.js"; export { default as getNextNonSpaceNonCommentCharacter } from "./get-next-non-space-non-comment-character.js"; +export { default as getPreferredQuote } from "./get-preferred-quote.js"; export { default as getStringWidth } from "./get-string-width.js"; export { default as hasNewline } from "./has-newline.js"; export { default as hasNewlineInRange } from "./has-newline-in-range.js"; diff --git a/tests/integration/__tests__/util-shared.js b/tests/integration/__tests__/util-shared.js index 2140db107..4fdf3ab37 100644 --- a/tests/integration/__tests__/util-shared.js +++ b/tests/integration/__tests__/util-shared.js @@ -26,6 +26,7 @@ test("shared util has correct structure", () => { "function", ); expect(typeof sharedUtil.makeString).toBe("function"); + expect(typeof sharedUtil.getPreferredQuote).toBe("function"); }); test("sharedUtil.getMaxContinuousCount", () => { @@ -229,3 +230,30 @@ test("sharedUtil.makeString", () => { ), ).toBe(`${SINGLE_QUOTE}a${SINGLE_QUOTE}`); }); + +test("sharedUtil.getPreferredQuote", () => { + const { getPreferredQuote } = sharedUtil; + const DOUBLE_QUOTE = '"'; + const SINGLE_QUOTE = "'"; + + expect(getPreferredQuote(``, true)).toBe(SINGLE_QUOTE); + expect(getPreferredQuote(``, false)).toBe(DOUBLE_QUOTE); + expect(getPreferredQuote(``, DOUBLE_QUOTE)).toBe(DOUBLE_QUOTE); + expect(getPreferredQuote(``, SINGLE_QUOTE)).toBe(SINGLE_QUOTE); + expect(getPreferredQuote(`'Hello' "World" 'Test'`, SINGLE_QUOTE)).toBe( + DOUBLE_QUOTE, + ); + expect(getPreferredQuote(`"Hello" 'World' "Test"`, DOUBLE_QUOTE)).toBe( + SINGLE_QUOTE, + ); + expect(getPreferredQuote(`"Hello" "World" "Test"`, SINGLE_QUOTE)).toBe( + SINGLE_QUOTE, + ); + expect(getPreferredQuote(`'Hello' 'World' 'Test'`, DOUBLE_QUOTE)).toBe( + DOUBLE_QUOTE, + ); + expect(getPreferredQuote(`'Hello' "World"`, SINGLE_QUOTE)).toBe(SINGLE_QUOTE); + expect(getPreferredQuote(`"Hello" 'World'`, DOUBLE_QUOTE)).toBe(DOUBLE_QUOTE); + expect(getPreferredQuote(`Hello World`, true)).toBe(SINGLE_QUOTE); + expect(getPreferredQuote(`Hello World`, false)).toBe(DOUBLE_QUOTE); +});