diff --git a/.README/README.md b/.README/README.md
index e6c3729..ec7c293 100644
--- a/.README/README.md
+++ b/.README/README.md
@@ -174,6 +174,7 @@ When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/d
{"gitdown": "include", "file": "./rules/no-weak-types.md"}
{"gitdown": "include", "file": "./rules/object-type-curly-spacing.md"}
{"gitdown": "include", "file": "./rules/object-type-delimiter.md"}
+{"gitdown": "include", "file": "./rules/quotes.md"}
{"gitdown": "include", "file": "./rules/require-compound-type-alias.md"}
{"gitdown": "include", "file": "./rules/require-exact-type.md"}
{"gitdown": "include", "file": "./rules/require-indexer-name.md"}
diff --git a/.README/rules/quotes.md b/.README/rules/quotes.md
new file mode 100644
index 0000000..fc803fe
--- /dev/null
+++ b/.README/rules/quotes.md
@@ -0,0 +1,12 @@
+### `quotes`
+
+Enforces single quotes or double quotes around string literals.
+
+#### Options
+
+The rule has string options of:
+
+* `"double"` (default) requires double quotes around string literals.
+* `"single"` requires single quotes around string literals.
+
+
diff --git a/README.md b/README.md
index 276ceb1..aca2fd1 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,7 @@
* [`no-weak-types`](#eslint-plugin-flowtype-rules-no-weak-types)
* [`object-type-curly-spacing`](#eslint-plugin-flowtype-rules-object-type-curly-spacing)
* [`object-type-delimiter`](#eslint-plugin-flowtype-rules-object-type-delimiter)
+ * [`quotes`](#eslint-plugin-flowtype-rules-quotes)
* [`require-compound-type-alias`](#eslint-plugin-flowtype-rules-require-compound-type-alias)
* [`require-exact-type`](#eslint-plugin-flowtype-rules-require-exact-type)
* [`require-indexer-name`](#eslint-plugin-flowtype-rules-require-indexer-name)
@@ -2836,12 +2837,79 @@ type Foo = { a: Foo, b: Bar }
+
+### quotes
+
+Enforces single quotes or double quotes around string literals.
+
+
+#### Options
+
+The rule has string options of:
+
+* `"double"` (default) requires double quotes around string literals.
+* `"single"` requires single quotes around string literals.
+
+The following patterns are considered problems:
+
+```js
+type T = 'hi'
+// Message: String literals must use double quote.
+
+// Options: ["double"]
+type T = { test: 'hello' | 'test' }
+// Message: String literals must use double quote.
+// Message: String literals must use double quote.
+
+// Options: ["double"]
+type T = { test: "hello" | 'test', t: 'hello' }
+// Message: String literals must use double quote.
+// Message: String literals must use double quote.
+
+// Options: ["single"]
+type T = "hi"
+// Message: String literals must use single quote.
+
+// Options: ["single"]
+type T = { test: "hello" | "test" }
+// Message: String literals must use single quote.
+// Message: String literals must use single quote.
+
+// Options: ["single"]
+type T = { test: "hello" | 'test', t: 'hello' }
+// Message: String literals must use single quote.
+```
+
+The following patterns are not considered problems:
+
+```js
+// Options: ["double"]
+type T = "hi"
+
+// Options: ["double"]
+type T = { test: "hello" | "test" }
+
+// Options: ["double"]
+type T = { test: "hello" | "test", t: "hello" }
+
+// Options: ["single"]
+type FooType = 'hi'
+
+// Options: ["single"]
+type T = { test: 'hello' | 'test' }
+
+// Options: ["single"]
+type T = { test: 'hello' | 'test', t: 'hello' }
+```
+
+
+
### require-compound-type-alias
Requires to make a type alias for all [union](https://flow.org/en/docs/types/unions/) and [intersection](https://flow.org/en/docs/types/intersections/) types. If these are used in "raw" forms it might be tempting to just copy & paste them around the code. However, this brings sort of a source code pollution and unnecessary changes on several parts when these compound types need to be changed.
-
+
#### Options
The rule has two options:
@@ -2935,7 +3003,7 @@ _The `--fix` option on the command line automatically fixes problems reported by
This rule enforces [exact object types](https://flow.org/en/docs/types/objects/#toc-exact-object-types).
-
+
#### Options
The rule has one string option:
@@ -3088,7 +3156,7 @@ _The `--fix` option on the command line automatically fixes problems reported by
This rule validates Flow object indexer name.
-
+
#### Options
The rule has a string option:
@@ -3133,7 +3201,7 @@ type foo = { [string]: number };
This rule enforces explicit inexact object types.
-
+
#### Options
The rule has one string option:
@@ -3242,7 +3310,7 @@ type foo = number;
Requires that all function parameters have type annotations.
-
+
#### Options
You can skip all arrow functions by providing the `excludeArrowFunctions` option with `true`.
@@ -3602,7 +3670,7 @@ function Foo(props: {}) { return
}
Requires that functions have return type annotation.
-
+
#### Options
You can skip all arrow functions by providing the `excludeArrowFunctions` option with `true`.
@@ -3964,7 +4032,7 @@ async function * foo(): AsyncIterable { yield 2; }
Requires all type declarations to be at the top of the file, after any import declarations.
-
+
#### Options
The rule has a string option:
@@ -4041,7 +4109,7 @@ This rule validates Flow file annotations.
This rule can optionally report missing or missed placed annotations, common typos (e.g. `// @floww`), and enforce a consistent annotation style.
-
+
#### Options
The rule has a string option:
@@ -4234,7 +4302,7 @@ a;
Requires that all variable declarators have type annotations.
-
+
#### Options
You can exclude variables that match a certain regex by using `excludeVariableMatch`.
@@ -4401,7 +4469,7 @@ _The `--fix` option on the command line automatically fixes problems reported by
Enforces natural, case-insensitive sorting of Object annotations.
-
+
#### Options
The first option specifies sort order.
@@ -4753,7 +4821,7 @@ _The `--fix` option on the command line automatically fixes problems reported by
Enforces consistent spacing after the type annotation colon.
-
+
#### Options
This rule has a string argument.
@@ -6122,7 +6190,7 @@ type foo = {test: number}; type bar = {...$Exact}
Enforces a consistent naming pattern for type aliases.
-
+
#### Options
This rule requires a text RegExp:
@@ -6183,7 +6251,7 @@ import {type T, type U, type V} from '...';
import type {T, U, V} from '...';
```
-
+
#### Options
The rule has a string option:
diff --git a/src/index.js b/src/index.js
index 06c251e..51292ea 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,6 +20,7 @@ import noInternalFlowType from './rules/noInternalFlowType';
import noMixed from './rules/noMixed';
import objectTypeCurlySpacing from './rules/objectTypeCurlySpacing';
import objectTypeDelimiter from './rules/objectTypeDelimiter';
+import quotes from './rules/quotes';
import requireIndexerName from './rules/requireIndexerName';
import requireCompoundTypeAlias from './rules/requireCompoundTypeAlias';
import requireInexactType from './rules/requireInexactType';
@@ -66,6 +67,7 @@ const rules = {
'no-weak-types': noWeakTypes,
'object-type-curly-spacing': objectTypeCurlySpacing,
'object-type-delimiter': objectTypeDelimiter,
+ quotes,
'require-compound-type-alias': requireCompoundTypeAlias,
'require-exact-type': requireExactType,
'require-indexer-name': requireIndexerName,
@@ -117,6 +119,7 @@ export default {
'no-weak-types': 0,
'object-type-curly-spacing': 0,
'object-type-delimiter': 0,
+ quotes: 0,
'require-compound-type-alias': 0,
'require-exact-type': 0,
'require-parameter-type': 0,
diff --git a/src/rules/quotes.js b/src/rules/quotes.js
new file mode 100644
index 0000000..3ee2216
--- /dev/null
+++ b/src/rules/quotes.js
@@ -0,0 +1,51 @@
+const schema = [
+ {
+ enum: ['double', 'single'],
+ type: 'string',
+ },
+];
+
+const meta = {
+ fixable: 'code',
+};
+
+const create = (context) => {
+ const double = (context.options[0] || 'double') === 'double';
+ const sourceCode = context.getSourceCode();
+
+ return {
+ StringLiteralTypeAnnotation (node) {
+ if (double && sourceCode.text[node.range[0]] !== '"') {
+ // double
+ context.report({
+ fix: (fixer) => {
+ return [
+ fixer.replaceTextRange([node.range[0], node.range[0] + 1], '"'),
+ fixer.replaceTextRange([node.range[1] - 1, node.range[1]], '"'),
+ ];
+ },
+ message: 'String literals must use double quote.',
+ node,
+ });
+ } else if (!double && sourceCode.text[node.range[0]] !== '\'') {
+ // single
+ context.report({
+ fix: (fixer) => {
+ return [
+ fixer.replaceTextRange([node.range[0], node.range[0] + 1], '\''),
+ fixer.replaceTextRange([node.range[1] - 1, node.range[1]], '\''),
+ ];
+ },
+ message: 'String literals must use single quote.',
+ node,
+ });
+ }
+ },
+ };
+};
+
+export default {
+ create,
+ meta,
+ schema,
+};
diff --git a/tests/rules/assertions/quotes.js b/tests/rules/assertions/quotes.js
new file mode 100644
index 0000000..49f1cb8
--- /dev/null
+++ b/tests/rules/assertions/quotes.js
@@ -0,0 +1,129 @@
+export default {
+ invalid: [
+ {
+ code: 'type T = \'hi\'',
+ errors: [
+ {
+ message: 'String literals must use double quote.',
+ },
+ ],
+ output: 'type T = "hi"',
+ },
+ {
+ code: 'type T = { test: \'hello\' | \'test\' }',
+ errors: [
+ {
+ message: 'String literals must use double quote.',
+ },
+ {
+ message: 'String literals must use double quote.',
+ },
+ ],
+ options: ['double'],
+ output: 'type T = { test: "hello" | "test" }',
+ },
+ {
+ code: 'type T = { test: "hello" | \'test\', t: \'hello\' }',
+ errors: [
+ {
+ message: 'String literals must use double quote.',
+ },
+ {
+ message: 'String literals must use double quote.',
+ },
+ ],
+ options: ['double'],
+ output: 'type T = { test: "hello" | "test", t: "hello" }',
+ },
+ {
+ code: 'type T = "hi"',
+ errors: [
+ {
+ message: 'String literals must use single quote.',
+ },
+ ],
+ options: ['single'],
+ output: 'type T = \'hi\'',
+ },
+ {
+ code: 'type T = { test: "hello" | "test" }',
+ errors: [
+ {
+ message: 'String literals must use single quote.',
+ },
+ {
+ message: 'String literals must use single quote.',
+ },
+ ],
+ options: ['single'],
+ output: 'type T = { test: \'hello\' | \'test\' }',
+ },
+ {
+ code: 'type T = { test: "hello" | \'test\', t: \'hello\' }',
+ errors: [
+ {
+ message: 'String literals must use single quote.',
+ },
+ ],
+ options: ['single'],
+ output: 'type T = { test: \'hello\' | \'test\', t: \'hello\' }',
+ },
+ ],
+ misconfigured: [
+ {
+ errors: [
+ {
+ data: 'temporarily',
+ dataPath: '[0]',
+ keyword: 'enum',
+ message: 'should be equal to one of the allowed values',
+ params: {
+ allowedValues: [
+ 'double',
+ 'single',
+ ],
+ },
+ parentSchema: {
+ enum: [
+ 'double',
+ 'single',
+ ],
+ type: 'string',
+ },
+ schema: [
+ 'double',
+ 'single',
+ ],
+ schemaPath: '#/items/0/enum',
+ },
+ ],
+ options: ['temporarily'],
+ },
+ ],
+ valid: [
+ {
+ code: 'type T = "hi"',
+ options: ['double'],
+ },
+ {
+ code: 'type T = { test: "hello" | "test" }',
+ options: ['double'],
+ },
+ {
+ code: 'type T = { test: "hello" | "test", t: "hello" }',
+ options: ['double'],
+ },
+ {
+ code: 'type FooType = \'hi\'',
+ options: ['single'],
+ },
+ {
+ code: 'type T = { test: \'hello\' | \'test\' }',
+ options: ['single'],
+ },
+ {
+ code: 'type T = { test: \'hello\' | \'test\', t: \'hello\' }',
+ options: ['single'],
+ },
+ ],
+};
diff --git a/tests/rules/index.js b/tests/rules/index.js
index 0383654..b030073 100644
--- a/tests/rules/index.js
+++ b/tests/rules/index.js
@@ -31,6 +31,7 @@ const reportingRules = [
'no-mixed',
'object-type-curly-spacing',
'object-type-delimiter',
+ 'quotes',
'require-compound-type-alias',
'require-inexact-type',
'require-indexer-name',