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

Change default of singleQuote to true #7466

Closed
wants to merge 15 commits into from
  •  
  •  
  •  
18 changes: 18 additions & 0 deletions changelog_unreleased/api/pr-7466.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#### Change default value for `singleQuotes` to `true` ([#7466](https://github.com/prettier/prettier/pull/7466) by [@karlhorky](https://github.com/karlhorky))

[Since version 0.0.1](https://github.com/prettier/prettier/commit/599b4311bb6be9204689a7725d37d6fdfca770aa), Prettier has an [option](https://prettier.io/docs/en/options.html#quotes) to use single quotes instead of double quotes.
Since version 2.0, the default of this option changes from `false` to `true`.

<!-- prettier-ignore -->
```js
// Input
const foo = 'bar';
// Prettier stable
const foo = "bar";
// Prettier master
const foo = 'bar';
```

The JavaScript ecosystem has largely standardized on single quotes, with it being the most popular style seen in the wild.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People are going to ask for sources on this.

Copy link
Contributor Author

@karlhorky karlhorky Jan 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, interesting perspective - I think they won't. I think that most JavaScript developers have already had this experience of single quotes being the norm by trolling through documentation and examples from all over the place.

Copy link
Contributor Author

@karlhorky karlhorky Jan 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it's not about your opinion or my opinion, so maybe we can get some statistics together on this!

Some sources:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will ask for some help in #4102.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that most JavaScript developers have already had this experience of single quotes being the norm by trolling through documentation

I write JS every day, and I honestly have no clue what’s the norm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will continue my research (and get some other people to help too). Single quotes are almost everywhere, so collecting them isn't tough to do.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Microsoft is really the only counter-example I can think of. They use doubled quotes.

The typescript source code: https://github.com/microsoft/TypeScript/blob/master/src/tsserver/server.ts

The typescript documentation: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html

Copy link
Contributor Author

@karlhorky karlhorky Jan 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@styfle Thanks! I've added this to the list:

#4102 (comment)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karlhorky Maybe you could move the content of that comment into the original post because github auto-collapses comments in the middle so its unlikely someone will see that who is just finding this PR (like myself).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I moved it yesterday already actually, under the link text "my review of the ecosystem"


If the old behavior is still preferred, please configure Prettier with `{ "singleQuotes": false }`.
4 changes: 3 additions & 1 deletion docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ Valid options:

## Quotes

_The default value changed from `false` to `true` in v2.0.0_

Use single quotes instead of double quotes.

Notes:
Expand All @@ -67,7 +69,7 @@ See the [strings rationale](rationale.md#strings) for more information.

| Default | CLI Override | API Override |
| ------- | ---------------- | --------------------- |
| `false` | `--single-quote` | `singleQuote: <bool>` |
| `true` | `--single-quote` | `singleQuote: <bool>` |

## Quote Props

Expand Down
2 changes: 1 addition & 1 deletion docs/rationale.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The first requirement of Prettier is to output valid code that has the exact sam

### Strings

Double or single quotes? Prettier chooses the one which results in the fewest number of escapes. `"It's gettin' better!"`, not `'It\'s gettin\' better!'`. In case of a tie, Prettier defaults to double quotes (but that can be changed via the [`--single-quote`](options.html#quotes) option).
Double or single quotes? Prettier follows the JavaScript ecosystem, which has largely standardized on single quotes, with it being the most popular style seen in the wild.
thorn0 marked this conversation as resolved.
Show resolved Hide resolved

JSX has its own option for quotes: [`--jsx-single-quote`](options.html#jsx-quotes).
JSX takes its roots from HTML, where the dominant use of quotes for attributes is double quotes. Browser developer tools also follow this convention by always displaying HTML with double quotes, even if the source code uses single quotes. A separate option allows using single quotes for JS and double quotes for "HTML" (JSX).
Expand Down
5 changes: 4 additions & 1 deletion src/common/common-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ module.exports = {
since: "0.0.0",
category: CATEGORY_COMMON,
type: "boolean",
default: false,
default: [
{ since: "0.0.0", value: false },
{ since: "2.0.0", value: true }
],
description: "Use single quotes instead of double quotes."
},
proseWrap: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class TestComponent {}

=====================================output=====================================
@Component({
selector: "app-test",
selector: 'app-test',
template: \`
<ul>
<li>test</li>
Expand Down Expand Up @@ -75,7 +75,7 @@ class TestComponent {}

=====================================output=====================================
@Component({
selector: "app-test",
selector: 'app-test',
template: \`
<ul>
<li>test</li>
Expand Down
18 changes: 9 additions & 9 deletions tests/angular_interpolation/__snapshots__/jsfmt.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ trailingComma: "none"
a[b | c],
($students | async).items,
($students | async)(),
myData | myPipe: "arg1":"arg2":"arg3",
myData | myPipe: 'arg1':'arg2':'arg3',
value
| pipeA
: {
Expand All @@ -122,8 +122,8 @@ trailingComma: "none"
}
| aaa,
(hideLinqPanel
? "ReportSelection.HideShowLabel_Show.String"
: "ReportSelection.HideShowLabel_Hide.String"
? 'ReportSelection.HideShowLabel_Show.String'
: 'ReportSelection.HideShowLabel_Hide.String'
) | localize: localizationSection
]
================================================================================
Expand Down Expand Up @@ -175,7 +175,7 @@ printWidth: 80
a[b | c],
($students | async).items,
($students | async)(),
myData | myPipe: "arg1":"arg2":"arg3",
myData | myPipe: 'arg1':'arg2':'arg3',
value
| pipeA
: {
Expand All @@ -188,8 +188,8 @@ printWidth: 80
}
| aaa,
(hideLinqPanel
? "ReportSelection.HideShowLabel_Show.String"
: "ReportSelection.HideShowLabel_Hide.String"
? 'ReportSelection.HideShowLabel_Show.String'
: 'ReportSelection.HideShowLabel_Hide.String'
) | localize: localizationSection
]
================================================================================
Expand Down Expand Up @@ -242,7 +242,7 @@ trailingComma: "all"
a[b | c],
($students | async).items,
($students | async)(),
myData | myPipe: "arg1":"arg2":"arg3",
myData | myPipe: 'arg1':'arg2':'arg3',
value
| pipeA
: {
Expand All @@ -255,8 +255,8 @@ trailingComma: "all"
}
| aaa,
(hideLinqPanel
? "ReportSelection.HideShowLabel_Show.String"
: "ReportSelection.HideShowLabel_Hide.String"
? 'ReportSelection.HideShowLabel_Show.String'
: 'ReportSelection.HideShowLabel_Hide.String'
) | localize: localizationSection
]
================================================================================
Expand Down
54 changes: 27 additions & 27 deletions tests/arrow-call/__snapshots__/jsfmt.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -56,33 +56,33 @@ const testResults = results.testResults.map((testResult) =>
formatResult(testResult, formatter, reporter)
);

it("mocks regexp instances", () => {
it('mocks regexp instances', () => {
expect(() =>
moduleMocker.generateFromMetadata(moduleMocker.getMetadata(/a/))
).not.toThrow();
});

expect(() => asyncRequest({ url: "/test-endpoint" })).toThrowError(
expect(() => asyncRequest({ url: '/test-endpoint' })).toThrowError(
/Required parameter/
);

expect(() =>
asyncRequest({ url: "/test-endpoint-but-with-a-long-url" })
asyncRequest({ url: '/test-endpoint-but-with-a-long-url' })
).toThrowError(/Required parameter/);

expect(() =>
asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" })
asyncRequest({ url: '/test-endpoint-but-with-a-suuuuuuuuper-long-url' })
).toThrowError(/Required parameter/);

expect(() =>
asyncRequest({ type: "foo", url: "/test-endpoint" })
asyncRequest({ type: 'foo', url: '/test-endpoint' })
).not.toThrowError();

expect(() =>
asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" })
asyncRequest({ type: 'foo', url: '/test-endpoint-but-with-a-long-url' })
).not.toThrowError();

const a = Observable.fromPromise(axiosInstance.post("/carts/mine")).map(
const a = Observable.fromPromise(axiosInstance.post('/carts/mine')).map(
(response) => response.data
);

Expand All @@ -103,8 +103,8 @@ const composition = (ViewComponent, ContainerComponent) =>

promise.then((result) =>
result.veryLongVariable.veryLongPropertyName > someOtherVariable
? "ok"
: "fail"
? 'ok'
: 'fail'
);

================================================================================
Expand Down Expand Up @@ -167,33 +167,33 @@ const testResults = results.testResults.map((testResult) =>
formatResult(testResult, formatter, reporter),
);

it("mocks regexp instances", () => {
it('mocks regexp instances', () => {
expect(() =>
moduleMocker.generateFromMetadata(moduleMocker.getMetadata(/a/)),
).not.toThrow();
});

expect(() => asyncRequest({ url: "/test-endpoint" })).toThrowError(
expect(() => asyncRequest({ url: '/test-endpoint' })).toThrowError(
/Required parameter/,
);

expect(() =>
asyncRequest({ url: "/test-endpoint-but-with-a-long-url" }),
asyncRequest({ url: '/test-endpoint-but-with-a-long-url' }),
).toThrowError(/Required parameter/);

expect(() =>
asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" }),
asyncRequest({ url: '/test-endpoint-but-with-a-suuuuuuuuper-long-url' }),
).toThrowError(/Required parameter/);

expect(() =>
asyncRequest({ type: "foo", url: "/test-endpoint" }),
asyncRequest({ type: 'foo', url: '/test-endpoint' }),
).not.toThrowError();

expect(() =>
asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" }),
asyncRequest({ type: 'foo', url: '/test-endpoint-but-with-a-long-url' }),
).not.toThrowError();

const a = Observable.fromPromise(axiosInstance.post("/carts/mine")).map(
const a = Observable.fromPromise(axiosInstance.post('/carts/mine')).map(
(response) => response.data,
);

Expand All @@ -214,8 +214,8 @@ const composition = (ViewComponent, ContainerComponent) =>

promise.then((result) =>
result.veryLongVariable.veryLongPropertyName > someOtherVariable
? "ok"
: "fail",
? 'ok'
: 'fail',
);

================================================================================
Expand Down Expand Up @@ -278,33 +278,33 @@ const testResults = results.testResults.map((testResult) =>
formatResult(testResult, formatter, reporter)
);

it("mocks regexp instances", () => {
it('mocks regexp instances', () => {
expect(() =>
moduleMocker.generateFromMetadata(moduleMocker.getMetadata(/a/))
).not.toThrow();
});

expect(() => asyncRequest({ url: "/test-endpoint" })).toThrowError(
expect(() => asyncRequest({ url: '/test-endpoint' })).toThrowError(
/Required parameter/
);

expect(() =>
asyncRequest({ url: "/test-endpoint-but-with-a-long-url" })
asyncRequest({ url: '/test-endpoint-but-with-a-long-url' })
).toThrowError(/Required parameter/);

expect(() =>
asyncRequest({ url: "/test-endpoint-but-with-a-suuuuuuuuper-long-url" })
asyncRequest({ url: '/test-endpoint-but-with-a-suuuuuuuuper-long-url' })
).toThrowError(/Required parameter/);

expect(() =>
asyncRequest({ type: "foo", url: "/test-endpoint" })
asyncRequest({ type: 'foo', url: '/test-endpoint' })
).not.toThrowError();

expect(() =>
asyncRequest({ type: "foo", url: "/test-endpoint-but-with-a-long-url" })
asyncRequest({ type: 'foo', url: '/test-endpoint-but-with-a-long-url' })
).not.toThrowError();

const a = Observable.fromPromise(axiosInstance.post("/carts/mine")).map(
const a = Observable.fromPromise(axiosInstance.post('/carts/mine')).map(
(response) => response.data
);

Expand All @@ -325,8 +325,8 @@ const composition = (ViewComponent, ContainerComponent) =>

promise.then((result) =>
result.veryLongVariable.veryLongPropertyName > someOtherVariable
? "ok"
: "fail"
? 'ok'
: 'fail'
);

================================================================================
Expand Down
36 changes: 18 additions & 18 deletions tests/arrows/__snapshots__/jsfmt.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ function render() {
}

jest.mock(
"../SearchSource",
'../SearchSource',
() =>
class {
findMatchingTests(pattern) {
Expand Down Expand Up @@ -1478,7 +1478,7 @@ function render() {
}

jest.mock(
"../SearchSource",
'../SearchSource',
() =>
class {
findMatchingTests(pattern) {
Expand Down Expand Up @@ -1849,11 +1849,11 @@ export const bem = (block) =>
*/
(modifier) =>
[
".",
'.',
css(block),
element ? \`__\${css(element)}\` : "",
modifier ? \`--\${css(modifier)}\` : "",
].join("");
element ? \`__\${css(element)}\` : '',
modifier ? \`--\${css(modifier)}\` : '',
].join('');

<FlatList
renderItem={(
Expand Down Expand Up @@ -1922,11 +1922,11 @@ export const bem = block =>
*/
modifier =>
[
".",
'.',
css(block),
element ? \`__\${css(element)}\` : "",
modifier ? \`--\${css(modifier)}\` : "",
].join("");
element ? \`__\${css(element)}\` : '',
modifier ? \`--\${css(modifier)}\` : '',
].join('');

<FlatList
renderItem={(
Expand Down Expand Up @@ -2082,10 +2082,10 @@ const foo = () => {
=====================================output=====================================
const foo = () => {
expect(arg1, arg2, arg3).toEqual({
message: "test",
messageType: "SMS",
status: "Unknown",
created: "11/01/2017 13:36",
message: 'test',
messageType: 'SMS',
status: 'Unknown',
created: '11/01/2017 13:36',
});
};

Expand All @@ -2106,10 +2106,10 @@ const foo = () => {
=====================================output=====================================
const foo = () => {
expect(arg1, arg2, arg3).toEqual({
message: "test",
messageType: "SMS",
status: "Unknown",
created: "11/01/2017 13:36",
message: 'test',
messageType: 'SMS',
status: 'Unknown',
created: '11/01/2017 13:36',
});
};

Expand Down
2 changes: 1 addition & 1 deletion tests/arrows_bind/__snapshots__/jsfmt.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ a => ({}::b()\`\`[''].c++ && 0 ? 0 : 0);
a::(b => c);

=====================================output=====================================
(a) => ({}::b()\`\`[""].c++ && 0 ? 0 : 0);
(a) => ({}::b()\`\`[''].c++ && 0 ? 0 : 0);
((a) => b)::c;
a::((b) => c);

Expand Down
2 changes: 1 addition & 1 deletion tests/assignment/__snapshots__/jsfmt.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const {
accessibilityModule: FooAccessibilityModule4,
} = foo || {};

({ prop: toAssign = "default" } = { prop: "propval" });
({ prop: toAssign = 'default' } = { prop: 'propval' });

================================================================================
`;
Expand Down