[Pkg-javascript-commits] [node-eslint-plugin-flowtype] 01/02: Import Upstream version 2.25.0
Thorsten Alteholz
alteholz at moszumanska.debian.org
Tue Sep 19 20:25:03 UTC 2017
This is an automated email from the git hooks/post-receive script.
alteholz pushed a commit to branch master
in repository node-eslint-plugin-flowtype.
commit 482efd00e434a776641bdd63a952814a594c2ae0
Author: Thorsten Alteholz <debian at alteholz.de>
Date: Tue Sep 19 22:24:53 2017 +0200
Import Upstream version 2.25.0
---
.README/README.md | 161 +
.README/rules/boolean-style.md | 13 +
.README/rules/define-flow-type.md | 7 +
.README/rules/delimiter-dangle.md | 19 +
.README/rules/generic-spacing.md | 11 +
.README/rules/no-dupe-keys.md | 15 +
.README/rules/no-weak-types.md | 33 +
.README/rules/object-type-delimiter.md | 17 +
.README/rules/require-parameter-type.md | 53 +
.README/rules/require-return-type.md | 37 +
.README/rules/require-valid-file-annotation.md | 43 +
.README/rules/semi.md | 11 +
.README/rules/sort-keys.md | 33 +
.README/rules/space-after-type-colon.md | 9 +
.README/rules/space-before-generic-bracket.md | 11 +
.README/rules/space-before-type-colon.md | 9 +
.README/rules/type-id-match.md | 22 +
.README/rules/union-intersection-spacing.md | 11 +
.README/rules/use-flow-type.md | 7 +
.README/rules/valid-syntax.md | 5 +
.babelrc | 9 +
.eslintrc | 3 +
.gitignore | 12 +
.npmignore | 5 +
.scripts/release.sh | 61 +
.travis.yml | 18 +
CHANGELOG.md | 268 ++
CONTRIBUTING.md | 52 +
LICENSE | 24 +
README.md | 3249 ++++++++++++++++++++
bin/readmeAssertions.js | 84 +
package.json | 57 +
src/configs/recommended.json | 44 +
src/index.js | 67 +
src/rules/booleanStyle.js | 29 +
src/rules/defineFlowType.js | 64 +
src/rules/delimiterDangle.js | 105 +
src/rules/genericSpacing.js | 78 +
src/rules/noDupeKeys.js | 32 +
src/rules/noWeakTypes.js | 42 +
src/rules/objectTypeDelimiter.js | 59 +
src/rules/requireParameterType.js | 47 +
src/rules/requireReturnType.js | 83 +
src/rules/requireValidFileAnnotation.js | 66 +
src/rules/semi.js | 52 +
src/rules/sortKeys.js | 91 +
src/rules/spaceAfterTypeColon.js | 7 +
src/rules/spaceBeforeGenericBracket.js | 47 +
src/rules/spaceBeforeTypeColon.js | 7 +
src/rules/typeColonSpacing/evaluateFunctions.js | 14 +
.../typeColonSpacing/evaluateObjectTypeIndexer.js | 21 +
.../typeColonSpacing/evaluateObjectTypeProperty.js | 42 +
src/rules/typeColonSpacing/evaluateReturnType.js | 16 +
.../typeColonSpacing/evaluateTypeCastExpression.js | 11 +
src/rules/typeColonSpacing/evaluateTypical.js | 27 +
src/rules/typeColonSpacing/index.js | 18 +
src/rules/typeColonSpacing/reporter.js | 45 +
src/rules/typeIdMatch.js | 22 +
src/rules/unionIntersectionSpacing.js | 67 +
src/rules/useFlowType.js | 36 +
src/rules/validSyntax.js | 27 +
src/utilities/getParameterName.js | 52 +
src/utilities/getTokenAfterParens.js | 13 +
src/utilities/getTokenBeforeParens.js | 13 +
src/utilities/index.js | 10 +
src/utilities/isFlowFile.js | 13 +
src/utilities/isFlowFileAnnotation.js | 13 +
src/utilities/iterateFunctionNodes.js | 12 +
src/utilities/quoteName.js | 3 +
src/utilities/spacingFixers.js | 39 +
tests/rules/assertions/booleanStyle.js | 34 +
tests/rules/assertions/defineFlowType.js | 219 ++
tests/rules/assertions/delimiterDangle.js | 512 +++
tests/rules/assertions/genericSpacing.js | 117 +
tests/rules/assertions/noDupeKeys.js | 17 +
tests/rules/assertions/noWeakTypes.js | 251 ++
tests/rules/assertions/objectTypeDelimiter.js | 147 +
tests/rules/assertions/requireParameterType.js | 195 ++
tests/rules/assertions/requireReturnType.js | 476 +++
.../rules/assertions/requireValidFileAnnotation.js | 146 +
tests/rules/assertions/semi.js | 55 +
tests/rules/assertions/sortKeys.js | 84 +
tests/rules/assertions/spaceAfterTypeColon.js | 1014 ++++++
.../rules/assertions/spaceBeforeGenericBracket.js | 41 +
tests/rules/assertions/spaceBeforeTypeColon.js | 845 +++++
tests/rules/assertions/typeIdMatch.js | 34 +
tests/rules/assertions/unionIntersectionSpacing.js | 202 ++
tests/rules/assertions/useFlowType.js | 190 ++
tests/rules/assertions/validSyntax.js | 13 +
tests/rules/index.js | 51 +
90 files changed, 10446 insertions(+)
diff --git a/.README/README.md b/.README/README.md
new file mode 100644
index 0000000..a63c691
--- /dev/null
+++ b/.README/README.md
@@ -0,0 +1,161 @@
+# eslint-plugin-flowtype
+
+[![NPM version](http://img.shields.io/npm/v/eslint-plugin-flowtype.svg?style=flat-square)](https://www.npmjs.org/package/eslint-plugin-flowtype)
+[![Travis build status](http://img.shields.io/travis/gajus/eslint-plugin-flowtype/master.svg?style=flat-square)](https://travis-ci.org/gajus/eslint-plugin-flowtype)
+[![js-canonical-style](https://img.shields.io/badge/code%20style-canonical-blue.svg?style=flat-square)](https://github.com/gajus/canonical)
+
+[Flow type](http://flowtype.org/) linting rules for ESLint.
+
+{"gitdown": "contents"}
+
+## Installation
+
+1. Install [ESLint](https://www.github.com/eslint/eslint).
+1. Install [`babel-eslint`](https://github.com/babel/babel-eslint) parser (ESLint parser [does not support type annotations](https://github.com/eslint/eslint/issues/2157)).
+1. Install [`eslint-plugin-flowtype`](https://github.com/gajus/eslint-plugin-flowtype) plugin.
+
+<!-- -->
+
+```sh
+npm install eslint
+npm install babel-eslint
+npm install eslint-plugin-flowtype
+```
+
+## Configuration
+
+1. Set `parser` property to `babel-eslint`.
+1. Add `plugins` section and specify `eslint-plugin-flowtype` as a plugin.
+1. Enable rules.
+
+<!-- -->
+
+```json
+{
+ "parser": "babel-eslint",
+ "plugins": [
+ "flowtype"
+ ],
+ "rules": {
+ "flowtype/boolean-style": [
+ 2,
+ "boolean"
+ ],
+ "flowtype/define-flow-type": 1,
+ "flowtype/delimiter-dangle": [
+ 2,
+ "never"
+ ],
+ "flowtype/generic-spacing": [
+ 2,
+ "never"
+ ],
+ "flowtype/no-weak-types": 2,
+ "flowtype/object-type-delimiter": [
+ 2,
+ "comma"
+ ],
+ "flowtype/require-parameter-type": 2,
+ "flowtype/require-return-type": [
+ 2,
+ "always",
+ {
+ "annotateUndefined": "never"
+ }
+ ],
+ "flowtype/require-valid-file-annotation": 2,
+ "flowtype/semi": [
+ 2,
+ "always"
+ ],
+ "flowtype/space-after-type-colon": [
+ 2,
+ "always"
+ ],
+ "flowtype/space-before-generic-bracket": [
+ 2,
+ "never"
+ ],
+ "flowtype/space-before-type-colon": [
+ 2,
+ "never"
+ ],
+ "flowtype/type-id-match": [
+ 2,
+ "^([A-Z][a-z0-9]+)+Type$"
+ ],
+ "flowtype/union-intersection-spacing": [
+ 2,
+ "always"
+ ],
+ "flowtype/use-flow-type": 1,
+ "flowtype/valid-syntax": 1
+ },
+ "settings": {
+ "flowtype": {
+ "onlyFilesWithFlowAnnotation": false
+ }
+ }
+}
+```
+
+### Shareable configurations
+
+#### Recommended
+
+This plugin exports a [recommended configuration](./src/configs/recommended.json) that enforces Flow type good practices.
+
+To enable this configuration use the extends property in your `.eslintrc` config file:
+
+```json
+{
+ "extends": [
+ "plugin:flowtype/recommended"
+ ],
+ "plugins": [
+ "flowtype"
+ ]
+}
+```
+
+See [ESLint documentation](http://eslint.org/docs/user-guide/configuring#extending-configuration-files) for more information about extending configuration files.
+
+## Settings
+
+### `onlyFilesWithFlowAnnotation`
+
+When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/docs/about-flow.html#gradual) in the first comment.
+
+```js
+{
+ "settings": {
+ "flowtype": {
+ "onlyFilesWithFlowAnnotation": true
+ }
+ }
+}
+```
+
+## Rules
+
+<!-- Rules are sorted alphabetically. -->
+
+{"gitdown": "include", "file": "./rules/boolean-style.md"}
+{"gitdown": "include", "file": "./rules/define-flow-type.md"}
+{"gitdown": "include", "file": "./rules/delimiter-dangle.md"}
+{"gitdown": "include", "file": "./rules/generic-spacing.md"}
+{"gitdown": "include", "file": "./rules/no-dupe-keys.md"}
+{"gitdown": "include", "file": "./rules/no-weak-types.md"}
+{"gitdown": "include", "file": "./rules/object-type-delimiter.md"}
+{"gitdown": "include", "file": "./rules/require-parameter-type.md"}
+{"gitdown": "include", "file": "./rules/require-return-type.md"}
+{"gitdown": "include", "file": "./rules/require-valid-file-annotation.md"}
+{"gitdown": "include", "file": "./rules/semi.md"}
+{"gitdown": "include", "file": "./rules/sort-keys.md"}
+{"gitdown": "include", "file": "./rules/space-after-type-colon.md"}
+{"gitdown": "include", "file": "./rules/space-before-generic-bracket.md"}
+{"gitdown": "include", "file": "./rules/space-before-type-colon.md"}
+{"gitdown": "include", "file": "./rules/type-id-match.md"}
+{"gitdown": "include", "file": "./rules/union-intersection-spacing.md"}
+{"gitdown": "include", "file": "./rules/use-flow-type.md"}
+{"gitdown": "include", "file": "./rules/valid-syntax.md"}
diff --git a/.README/rules/boolean-style.md b/.README/rules/boolean-style.md
new file mode 100644
index 0000000..7637a23
--- /dev/null
+++ b/.README/rules/boolean-style.md
@@ -0,0 +1,13 @@
+### `boolean-style`
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces a particular style for boolean type annotations. This rule takes one argument.
+
+If it is `'boolean'` then a problem is raised when using `bool` instead of `boolean`.
+
+If it is `'bool'` then a problem is raised when using `boolean` instead of `bool`.
+
+The default value is `'boolean'`.
+
+<!-- assertions booleanStyle -->
diff --git a/.README/rules/define-flow-type.md b/.README/rules/define-flow-type.md
new file mode 100644
index 0000000..d103645
--- /dev/null
+++ b/.README/rules/define-flow-type.md
@@ -0,0 +1,7 @@
+### `define-flow-type`
+
+Marks Flow type identifiers as defined.
+
+Used to suppress [`no-undef`](http://eslint.org/docs/rules/no-undef) reporting of type identifiers.
+
+<!-- assertions defineFlowType -->
diff --git a/.README/rules/delimiter-dangle.md b/.README/rules/delimiter-dangle.md
new file mode 100644
index 0000000..46eb144
--- /dev/null
+++ b/.README/rules/delimiter-dangle.md
@@ -0,0 +1,19 @@
+### `delimiter-dangle`
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent use of trailing commas in Object and Tuple annotations.
+
+This rule takes one argument which mirrors ESLint's default `comma-dangle` rule.
+
+If it is `'never'` then a problem is raised when there is a trailing comma.
+
+If it is `'always'` then a problem is raised when there is no trailing comma.
+
+If it is `'always-multiline'` then a problem is raised when there is no trailing comma on a multi-line definition, or there _is_ a trailing comma on a single-line definition.
+
+If it is `'only-multiline'` then a problem is raised when there is a trailing comma on a single-line definition. It allows, but does not enforce, trailing commas on multi-line definitions.
+
+The default value is `'never'`.
+
+<!-- assertions delimiterDangle -->
diff --git a/.README/rules/generic-spacing.md b/.README/rules/generic-spacing.md
new file mode 100644
index 0000000..7254e48
--- /dev/null
+++ b/.README/rules/generic-spacing.md
@@ -0,0 +1,11 @@
+### `generic-spacing`
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing within generic type annotation parameters.
+
+This rule takes one argument. If it is `'never'` then a problem is raised when there is a space surrounding the generic type parameters. If it is `'always'` then a problem is raised when there is no space surrounding the generic type parameters.
+
+The default value is `'never'`.
+
+<!-- assertions genericSpacing -->
diff --git a/.README/rules/no-dupe-keys.md b/.README/rules/no-dupe-keys.md
new file mode 100644
index 0000000..447ecba
--- /dev/null
+++ b/.README/rules/no-dupe-keys.md
@@ -0,0 +1,15 @@
+### `no-dupe-keys`
+
+Checks for duplicate properties in Object annotations.
+
+This rule mirrors ESLint's [no-dupe-keys](http://eslint.org/docs/rules/no-dupe-keys) rule.
+
+```js
+{
+ "rules": {
+ "flowtype/no-dupe-keys": 2
+ }
+}
+```
+
+<!-- assertions noDupeKeys -->
diff --git a/.README/rules/no-weak-types.md b/.README/rules/no-weak-types.md
new file mode 100644
index 0000000..5005840
--- /dev/null
+++ b/.README/rules/no-weak-types.md
@@ -0,0 +1,33 @@
+### `no-weak-types`
+
+Warns against weak type annotations *any*, *Object* and *Function*.
+These types can cause flow to silently skip over portions of your code,
+which would have otherwise caused type errors.
+
+This rule optionally takes one argument, an object to configure which type warnings to enable. By default, all of the
+warnings are enabled. e.g. to disable the `any` warning (allowing it to exist in your code), while continuing to warn
+about `Object` and `Function`:
+
+```js
+{
+ "rules": {
+ "flowtype/no-weak-types": [2, {
+ "any": false,
+ "Object": true,
+ "Function": true
+ }]
+ }
+}
+
+// or, the following is equivalent as default is true:
+
+{
+ "rules": {
+ "flowtype/no-weak-types": [2, {
+ "any": false
+ }]
+ }
+}
+```
+
+<!-- assertions noWeakTypes -->
diff --git a/.README/rules/object-type-delimiter.md b/.README/rules/object-type-delimiter.md
new file mode 100644
index 0000000..41c1706
--- /dev/null
+++ b/.README/rules/object-type-delimiter.md
@@ -0,0 +1,17 @@
+### `object-type-delimiter`
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent separators between properties in Flow object types.
+
+This rule takes one argument.
+
+If it is `'comma'` then a problem is raised when using `;` as a separator.
+
+If it is `'semicolon'` then a problem is raised when using `,` as a separator.
+
+The default value is `'comma'`.
+
+_This rule is ported from `babel/flow-object-type`, however the default option was changed._
+
+<!-- assertions objectTypeDelimiter -->
diff --git a/.README/rules/require-parameter-type.md b/.README/rules/require-parameter-type.md
new file mode 100644
index 0000000..83bc065
--- /dev/null
+++ b/.README/rules/require-parameter-type.md
@@ -0,0 +1,53 @@
+### `require-parameter-type`
+
+Requires that all function parameters have type annotations.
+
+#### Options
+
+You can skip all arrow functions by providing the `excludeArrowFunctions` option with `true`.
+
+Alternatively, you can want to exclude only concise arrow functions (e.g. `x => x * 2`). Provide `excludeArrowFunctions` with `expressionsOnly` for this.
+
+```js
+{
+ "rules": {
+ "flowtype/require-parameter-type": [
+ 2,
+ {
+ "excludeArrowFunctions": true
+ }
+ ]
+ }
+}
+
+{
+ "rules": {
+ "flowtype/require-parameter-type": [
+ 2,
+ {
+ "excludeArrowFunctions": "expressionsOnly"
+ }
+ ]
+ }
+}
+```
+
+You can exclude parameters that match a certain regex by using `excludeParameterMatch`.
+
+```js
+{
+ "rules": {
+ "flowtype/require-parameter-type": [
+ 2,
+ {
+ "excludeParameterMatch": "^_"
+ }
+ ]
+ }
+}
+```
+
+This excludes all parameters that start with an underscore (`_`).
+The default pattern is `a^`, which doesn't match anything, i.e., all parameters are checked.
+
+<!-- assertions requireParameterType -->
diff --git a/.README/rules/require-return-type.md b/.README/rules/require-return-type.md
new file mode 100644
index 0000000..371a723
--- /dev/null
+++ b/.README/rules/require-return-type.md
@@ -0,0 +1,37 @@
+### `require-return-type`
+
+Requires that functions have return type annotation.
+
+#### Options
+
+You can skip all arrow functions by providing the `excludeArrowFunctions` option with `true`.
+
+Alternatively, you can want to exclude only concise arrow function (e.g. `() => 2`). Provide `excludeArrowFunctions` with `expressionsOnly` for this.
+
+```js
+{
+ "rules": {
+ "flowtype/require-return-type": [
+ 2,
+ "always",
+ {
+ "excludeArrowFunctions": true
+ }
+ ]
+ }
+}
+
+{
+ "rules": {
+ "flowtype/require-return-type": [
+ 2,
+ "always",
+ {
+ "excludeArrowFunctions": "expressionsOnly"
+ }
+ ]
+ }
+}
+```
+
+<!-- assertions requireReturnType -->
diff --git a/.README/rules/require-valid-file-annotation.md b/.README/rules/require-valid-file-annotation.md
new file mode 100644
index 0000000..02b973f
--- /dev/null
+++ b/.README/rules/require-valid-file-annotation.md
@@ -0,0 +1,43 @@
+### `require-valid-file-annotation`
+
+This rule validates Flow file annotations.
+
+This rule can optionally report missing or missed placed annotations, common typos (e.g. `// @floww`), and enforce a consistant annotation style.
+
+#### Options
+
+The rule has a string option:
+
+* `"never"` (default): Never report files that are missing an `@flow` annotation.
+* `"always"`: Always report files that are missing an `@flow` annotation
+
+This rule has an object option:
+
+* `"annotationStyle"` - Enforce a consistant file annotation style.
+ * `"none"` (default): Either annotation style is accepted.
+ * `"line"`: Require single line annotations (i.e. `// @flow`).
+ * `"block"`: Require block annotations (i.e. `/* @flow */`).
+
+```js
+{
+ "rules": {
+ "flowtype/require-valid-file-annotation": [
+ 2,
+ "always"
+ ]
+ }
+}
+
+{
+ "rules": {
+ "flowtype/require-valid-file-annotation": [
+ 2,
+ "always", {
+ "annotationStyle": "block"
+ }
+ ]
+ }
+}
+```
+
+<!-- assertions requireValidFileAnnotation -->
diff --git a/.README/rules/semi.md b/.README/rules/semi.md
new file mode 100644
index 0000000..1b6cae1
--- /dev/null
+++ b/.README/rules/semi.md
@@ -0,0 +1,11 @@
+### `semi`
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent use of semicolons after type aliases.
+
+This rule takes one argument. If it is `'never'` then a problem is raised when there is a semicolon after a type alias. If it is `'always'` then a problem is raised when there is no semicolon after a type alias.
+
+The default value is `'always'`.
+
+<!-- assertions semi -->
diff --git a/.README/rules/sort-keys.md b/.README/rules/sort-keys.md
new file mode 100644
index 0000000..a083bb6
--- /dev/null
+++ b/.README/rules/sort-keys.md
@@ -0,0 +1,33 @@
+### `sort-keys`
+
+Enforces sorting of Object annotations.
+
+This rule mirrors ESlint's [sort-keys](http://eslint.org/docs/rules/sort-keys) rule.
+
+#### Options
+
+The first option specifies sort order.
+
+* `"asc"` (default) - enforce ascending sort order.
+* `"desc"` - enforce descending sort order.
+
+The second option takes an object with two possible properties.
+
+* `caseSensitive` - if `true`, enforce case-sensitive sort order. Default is `true`.
+* `natural` - if `true`, enforce [natural sort order](https://en.wikipedia.org/wiki/Natural_sort_order). Default is `false`.
+
+```js
+{
+ "rules": {
+ "flowtype/sort-keys": [
+ 2,
+ "asc", {
+ "caseSensitive": true,
+ "natural": false
+ }
+ ]
+ }
+}
+```
+
+<!-- assertions sortKeys -->
diff --git a/.README/rules/space-after-type-colon.md b/.README/rules/space-after-type-colon.md
new file mode 100644
index 0000000..5b54edc
--- /dev/null
+++ b/.README/rules/space-after-type-colon.md
@@ -0,0 +1,9 @@
+### `space-after-type-colon`
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing after the type annotation colon.
+
+This rule takes one argument. If it is `'always'` then a problem is raised when there is no space after the type annotation colon. If it is `'never'` then a problem is raised when there is a space after the type annotation colon. The default value is `'always'`.
+
+<!-- assertions spaceAfterTypeColon -->
diff --git a/.README/rules/space-before-generic-bracket.md b/.README/rules/space-before-generic-bracket.md
new file mode 100644
index 0000000..305966a
--- /dev/null
+++ b/.README/rules/space-before-generic-bracket.md
@@ -0,0 +1,11 @@
+### `space-before-generic-bracket`
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing before the opening `<` of generic type annotation parameters.
+
+This rule takes one argument. If it is `'never'` then a problem is raised when there is a space before the `<`. If it is `'always'` then a problem is raised when there is no space before the `<`.
+
+The default value is `'never'`.
+
+<!-- assertions spaceBeforeGenericBracket -->
diff --git a/.README/rules/space-before-type-colon.md b/.README/rules/space-before-type-colon.md
new file mode 100644
index 0000000..1643ae0
--- /dev/null
+++ b/.README/rules/space-before-type-colon.md
@@ -0,0 +1,9 @@
+### `space-before-type-colon`
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing before the type annotation colon.
+
+This rule takes one argument. If it is `'always'` then a problem is raised when there is no space before the type annotation colon. If it is `'never'` then a problem is raised when there is a space before the type annotation colon. The default value is `'never'`.
+
+<!-- assertions spaceBeforeTypeColon -->
diff --git a/.README/rules/type-id-match.md b/.README/rules/type-id-match.md
new file mode 100644
index 0000000..6fe9302
--- /dev/null
+++ b/.README/rules/type-id-match.md
@@ -0,0 +1,22 @@
+### `type-id-match`
+
+Enforces a consistent naming pattern for type aliases.
+
+#### Options
+
+This rule needs a text RegExp to operate with Its signature is as follows:
+
+```js
+{
+ "rules": {
+ "flowtype/type-id-match": [
+ 2,
+ "^([A-Z][a-z0-9]*)+Type$"
+ ]
+ }
+}
+```
+
+`'^([A-Z][a-z0-9]*)+Type$$'` is the default pattern.
+
+<!-- assertions typeIdMatch -->
diff --git a/.README/rules/union-intersection-spacing.md b/.README/rules/union-intersection-spacing.md
new file mode 100644
index 0000000..a0e6cb3
--- /dev/null
+++ b/.README/rules/union-intersection-spacing.md
@@ -0,0 +1,11 @@
+### `union-intersection-spacing`
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing around union and intersection type separators (`|` and `&`).
+
+This rule takes one argument. If it is `'always'` then a problem is raised when there is no space around the separator. If it is `'never'` then a problem is raised when there is a space around the separator.
+
+The default value is `'always'`.
+
+<!-- assertions unionIntersectionSpacing -->
diff --git a/.README/rules/use-flow-type.md b/.README/rules/use-flow-type.md
new file mode 100644
index 0000000..35f77c7
--- /dev/null
+++ b/.README/rules/use-flow-type.md
@@ -0,0 +1,7 @@
+### `use-flow-type`
+
+Marks Flow [type alias](https://flowtype.org/docs/type-aliases.html) declarations as used.
+
+Used to suppress [`no-unused-vars`](http://eslint.org/docs/rules/no-unused-vars) errors that are triggered by type aliases.
+
+<!-- assertions useFlowType -->
diff --git a/.README/rules/valid-syntax.md b/.README/rules/valid-syntax.md
new file mode 100644
index 0000000..a0126e2
--- /dev/null
+++ b/.README/rules/valid-syntax.md
@@ -0,0 +1,5 @@
+### `valid-syntax`
+
+**Deprecated** Babylon (the Babel parser) v6.10.0 fixes parsing of the invalid syntax this plugin warned against.
+
+Checks for simple Flow syntax errors.
diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..d43233e
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,9 @@
+{
+ "presets": [
+ "es2015",
+ "stage-0"
+ ],
+ "plugins": [
+ "add-module-exports"
+ ]
+}
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..40288f8
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,3 @@
+{
+ "extends": "canonical"
+}
diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..5364199
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+node_modules
+coverage
+dist
+*.log
+.*
+!.eslintrc
+!.gitignore
+!.npmignore
+!.babelrc
+!.travis.yml
+!.README
+!.scripts
diff --git a/.npmignore b/.npmignore
new file mode 100755
index 0000000..e8add85
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,5 @@
+src
+tests
+coverage
+.*
+*.log
diff --git a/.scripts/release.sh b/.scripts/release.sh
new file mode 100755
index 0000000..68eb40f
--- /dev/null
+++ b/.scripts/release.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+set -ex
+
+if [[ $TRAVIS_PULL_REQUEST != "false" ]]; then
+ echo 'This is a pull request. Exiting the release script.'
+
+ exit 0
+fi
+
+if [[ -n $TRAVIS_TAG ]]; then
+ echo 'This is a tag release.'
+
+ # Use NPM_TOKEN to enable NPM authentication
+ set +x
+ echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
+ set -x
+
+ NODE_ENV=development npm install
+ NODE_ENV=production npm run build
+
+ npm publish
+ exit 0
+fi
+
+if [[ $TRAVIS_BRANCH != "master" ]]; then
+ echo 'This is not a master branch. Exiting the release script.'
+
+ exit 0
+fi
+
+if [[ $(git log --format=%B -n 1 $TRAVIS_COMMIT) == *"chore: release"* ]]; then
+ echo 'This is a tag release. Exiting the release script.'
+
+ exit 0
+fi;
+
+git config --global user.name 'continuous-deployment'
+git config --global user.email 'continuous-deployment at travis'
+
+# Use GITHUB_TOKEN to enable GitHub authentication
+git config credential.helper "store --file=.git/credentials"
+set +x
+echo "https://${GITHUB_TOKEN}:@github.com" > .git/credentials
+set -x
+
+git checkout master
+git merge $TRAVIS_COMMIT
+
+# Generate ./README.md from ./.README/README.md template.
+npm run documentation
+
+git add ./README.md
+git diff-index --quiet HEAD ./README.md || git commit --no-verify -m 'docs: update documentation' ./README.md
+
+# 1. bump the package.json version (based on your commit history)
+# 2. update CHANGELOG.md
+# 3. commit package.json and CHANGELOG.md
+# 4. tag the release
+standard-version --no-verify --message "chore: release %s"
+
+git push --follow-tags origin master
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..7570750
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+language: node_js
+node_js:
+ - 6
+ - 5
+ - 4
+before_install:
+ - npm config set depth 0
+ - npm install --global npm at 3
+notifications:
+ email: false
+sudo: false
+script:
+ - npm run test
+ - npm run lint
+ - npm run build
+ - conventional-changelog-lint --from=HEAD~$(git --no-pager rev-list master..HEAD --count)
+after_success:
+ - travis-after-all && ./.scripts/release.sh
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..31f4b8e
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,268 @@
+# Change Log
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+<a name="2.25.0"></a>
+# [2.25.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.24.0...v2.25.0) (2016-10-25)
+
+
+### Features
+
+* Add excludeParameterMatch option to require-parameter-type ([d9cfbbe](https://github.com/gajus/eslint-plugin-flowtype/commit/d9cfbbe))
+
+
+
+<a name="2.24.0"></a>
+# [2.24.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.23.1...v2.24.0) (2016-10-25)
+
+
+### Features
+
+* add additional tests for function return types ([795b3a4](https://github.com/gajus/eslint-plugin-flowtype/commit/795b3a4))
+
+
+
+<a name="2.23.1"></a>
+## [2.23.1](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.23.0...v2.23.1) (2016-10-25)
+
+
+### Bug Fixes
+
+* Support more properties in object-type-delimiter ([6b0a677](https://github.com/gajus/eslint-plugin-flowtype/commit/6b0a677))
+
+
+
+<a name="2.23.0"></a>
+# [2.23.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.22.0...v2.23.0) (2016-10-24)
+
+
+### Features
+
+* add object-type-delimiter rule ([a99721b](https://github.com/gajus/eslint-plugin-flowtype/commit/a99721b))
+
+
+
+<a name="2.22.0"></a>
+# [2.22.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.21.0...v2.22.0) (2016-10-24)
+
+
+### Features
+
+* ObjectTypeIndexer in spaceBeforeTypeColon & spaceAfterTypeColon ([82c87c4](https://github.com/gajus/eslint-plugin-flowtype/commit/82c87c4)), closes [#134](https://github.com/gajus/eslint-plugin-flowtype/issues/134)
+
+
+
+<a name="2.21.0"></a>
+# [2.21.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.20.0...v2.21.0) (2016-10-22)
+
+
+### Features
+
+* Add variance support to spaceBeforeTypeColon & spaceAfterTypeColon ([4a7f87f](https://github.com/gajus/eslint-plugin-flowtype/commit/4a7f87f)), closes [#137](https://github.com/gajus/eslint-plugin-flowtype/issues/137)
+
+
+
+<a name="2.20.0"></a>
+# [2.20.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.19.0...v2.20.0) (2016-10-06)
+
+
+### Features
+
+* add annotation enforcement option ([dd71ce8](https://github.com/gajus/eslint-plugin-flowtype/commit/dd71ce8))
+
+
+
+<a name="2.19.0"></a>
+# [2.19.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.18.2...v2.19.0) (2016-09-20)
+
+
+### Bug Fixes
+
+* parens in TypeCastExpression ([0e0081f](https://github.com/gajus/eslint-plugin-flowtype/commit/0e0081f))
+
+### Features
+
+* add rule `sort-keys` (fixes #104) ([f6b8deb](https://github.com/gajus/eslint-plugin-flowtype/commit/f6b8deb)), closes [#104](https://github.com/gajus/eslint-plugin-flowtype/issues/104)
+* check TypeCastExpressions in type colon spacing rules ([98839f0](https://github.com/gajus/eslint-plugin-flowtype/commit/98839f0))
+
+
+
+<a name="2.18.2"></a>
+## [2.18.2](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.18.1...v2.18.2) (2016-09-18)
+
+
+
+
+<a name="2.18.1"></a>
+## [2.18.1](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.18.0...v2.18.1) (2016-09-15)
+
+
+
+
+<a name="2.18.0"></a>
+# [2.18.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.17.1...v2.18.0) (2016-09-15)
+
+
+### Features
+
+* add rule `no-dupe-keys` (fixes #108) (#109) ([6a65de0](https://github.com/gajus/eslint-plugin-flowtype/commit/6a65de0)), closes [#108](https://github.com/gajus/eslint-plugin-flowtype/issues/108) [(#109](https://github.com/(/issues/109)
+
+
+
+<a name="2.17.1"></a>
+## [2.17.1](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.17.0...v2.17.1) (2016-09-12)
+
+
+### Bug Fixes
+
+* config file (json failing lint) ([eedcac7](https://github.com/gajus/eslint-plugin-flowtype/commit/eedcac7))
+* correct recommended config name ([35150d4](https://github.com/gajus/eslint-plugin-flowtype/commit/35150d4))
+* disable lint for one run ([3745498](https://github.com/gajus/eslint-plugin-flowtype/commit/3745498))
+
+
+
+<a name="2.17.0"></a>
+# [2.17.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.16.1...v2.17.0) (2016-09-12)
+
+
+### Features
+
+* define recommended configuration ([dc2e35b](https://github.com/gajus/eslint-plugin-flowtype/commit/dc2e35b))
+* export recommended configuration ([f7d7a21](https://github.com/gajus/eslint-plugin-flowtype/commit/f7d7a21))
+
+
+
+<a name="2.16.1"></a>
+## [2.16.1](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.16.0...v2.16.1) (2016-09-09)
+
+
+
+
+<a name="2.16.0"></a>
+# [2.16.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.15.0...v2.16.0) (2016-09-07)
+
+
+### Bug Fixes
+
+* `delimiter-dangle` with indexers ([9ff6f37](https://github.com/gajus/eslint-plugin-flowtype/commit/9ff6f37))
+* reported locations in `delimiter-dangle` ([06fbd92](https://github.com/gajus/eslint-plugin-flowtype/commit/06fbd92))
+
+### Features
+
+* add `delimiter-dangle` for trailing commas/semicolons ([788f480](https://github.com/gajus/eslint-plugin-flowtype/commit/788f480))
+
+
+
+<a name="2.15.0"></a>
+# [2.15.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.14.3...v2.15.0) (2016-09-05)
+
+
+### Features
+
+* options to prevent specific types in `no-weak-types` (#99) ([9c903ad](https://github.com/gajus/eslint-plugin-flowtype/commit/9c903ad))
+
+
+
+<a name="2.14.3"></a>
+## [2.14.3](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.14.2...v2.14.3) (2016-09-05)
+
+
+### Bug Fixes
+
+* ensure not to print private tokens ([1e41818](https://github.com/gajus/eslint-plugin-flowtype/commit/1e41818))
+
+
+
+<a name="2.14.2"></a>
+## [2.14.2](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.14.1...v2.14.2) (2016-09-05)
+
+
+### Bug Fixes
+
+* move tag check prior to branch check ([29b35d0](https://github.com/gajus/eslint-plugin-flowtype/commit/29b35d0))
+
+
+
+<a name="2.14.1"></a>
+## [2.14.1](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.14.0...v2.14.1) (2016-09-05)
+
+
+### Bug Fixes
+
+* add a condition to prevent empty commit ([2e6ddfa](https://github.com/gajus/eslint-plugin-flowtype/commit/2e6ddfa))
+* fix release script ([260b86b](https://github.com/gajus/eslint-plugin-flowtype/commit/260b86b))
+
+
+
+<a name="2.14.0"></a>
+# [2.14.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.13.0...v2.14.0) (2016-09-05)
+
+
+### Features
+
+* add new rule `no-weak-types` (#96) ([c1a94c5](https://github.com/gajus/eslint-plugin-flowtype/commit/c1a94c5))
+
+
+
+<a name="2.13.0"></a>
+# [2.13.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.12.1...v2.13.0) (2016-09-03)
+
+
+### Features
+
+* add new rule `boolean-style` (#98) ([1ab7902](https://github.com/gajus/eslint-plugin-flowtype/commit/1ab7902))
+
+
+
+<a name="2.12.1"></a>
+## [2.12.1](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.12.0...v2.12.1) (2016-09-01)
+
+
+### Bug Fixes
+
+* allow uppercase sequences in 'type-id-match' (#93) ([000b0d1](https://github.com/gajus/eslint-plugin-flowtype/commit/000b0d1))
+
+
+
+<a name="2.12.0"></a>
+# [2.12.0](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.11.5...v2.12.0) (2016-09-01)
+
+
+### Bug Fixes
+
+* add --no-verify to docs commit ([393643b](https://github.com/gajus/eslint-plugin-flowtype/commit/393643b))
+* add --no-verify to standard-version ([22a0559](https://github.com/gajus/eslint-plugin-flowtype/commit/22a0559))
+
+### Features
+
+* add new rule "semi" for semicolon linting (#95) ([ead974d](https://github.com/gajus/eslint-plugin-flowtype/commit/ead974d))
+
+
+
+<a name="2.11.5"></a>
+## [2.11.5](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.11.4...v2.11.5) (2016-09-01)
+
+
+
+<a name="2.11.4"></a>
+## [2.11.4](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.11.3...v2.11.4) (2016-08-23)
+
+
+
+<a name="2.11.3"></a>
+## [2.11.3](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.11.2...v2.11.3) (2016-08-23)
+
+
+### Bug Fixes
+
+* commit documentation changes ([15a8289](https://github.com/gajus/eslint-plugin-flowtype/commit/15a8289))
+
+
+
+<a name="2.11.2"></a>
+## [2.11.2](https://github.com/gajus/eslint-plugin-flowtype/compare/v2.11.1...v2.11.2) (2016-08-23)
+
+
+### Bug Fixes
+
+* make release.sh executable ([6fa6f89](https://github.com/gajus/eslint-plugin-flowtype/commit/6fa6f89))
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..6a39e87
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,52 @@
+# Contributing
+
+**`README.md` is a generated file. Do not edit it directly.** Edit the files inside `.README` instead.
+
+## Pre-Commit Hook
+
+When making a commit, the following Pre-Commit hooks run:
+
+* tests
+* lint
+* commit message validation (see "Commit Messages" below)
+
+## Commit Messages
+
+All commit messages must begin with one of the following prefixes:
+
+* `fix: `
+* `feat: `
+* `refactor: `
+* `docs: `
+* `chore: `
+
+The prefix is used to bump the correct segment of the version number automatically during deploy.
+
+## Tests
+
+Run them with `npm t`.
+
+## Lint
+
+Run with `npm run lint`.
+
+## Adding a Rule
+
+### Source & Tests
+
+1. Create a file in `tests/rules/assertions` named the `camelCase` version of your rule name with the following template:
+ * `export default { invalid: [], valid: [] }`
+2. Add your test file to `tests/index.js`
+3. Create a file in `src/rules` named the `camelCase` version of your rule name
+4. Add your rule file to `src/index.js`
+
+### Adding Documentation
+
+1. Create new file in `./README/rules/[rule-name].md`.
+ * Use [./.README/rules/require-valid-file-annotation.md](./.README/rules/require-valid-file-annotation.md) as a template.
+ * Ensure that rule documentation document includes `<!-- assertions spaceAfterTypeColon -->` declaration.
+1. Update [./.README/README.md](/.README/README.md) to include the new rule.
+
+A CI service will build and publish the new documentation.
+
+Note: The section "The following patterns are considered problems:" and "The following patterns are not considered problems:" is **generated automatically** using the test cases.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..183e8d8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2015, Gajus Kuizinas (http://gajus.com/)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Gajus Kuizinas (http://gajus.com/) nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ANUARY BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..937937b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3249 @@
+<a name="eslint-plugin-flowtype"></a>
+# eslint-plugin-flowtype
+
+[![NPM version](http://img.shields.io/npm/v/eslint-plugin-flowtype.svg?style=flat-square)](https://www.npmjs.org/package/eslint-plugin-flowtype)
+[![Travis build status](http://img.shields.io/travis/gajus/eslint-plugin-flowtype/master.svg?style=flat-square)](https://travis-ci.org/gajus/eslint-plugin-flowtype)
+[![js-canonical-style](https://img.shields.io/badge/code%20style-canonical-blue.svg?style=flat-square)](https://github.com/gajus/canonical)
+
+[Flow type](http://flowtype.org/) linting rules for ESLint.
+
+* [eslint-plugin-flowtype](#eslint-plugin-flowtype)
+ * [Installation](#eslint-plugin-flowtype-installation)
+ * [Configuration](#eslint-plugin-flowtype-configuration)
+ * [Shareable configurations](#eslint-plugin-flowtype-configuration-shareable-configurations)
+ * [Settings](#eslint-plugin-flowtype-settings)
+ * [`onlyFilesWithFlowAnnotation`](#eslint-plugin-flowtype-settings-onlyfileswithflowannotation)
+ * [Rules](#eslint-plugin-flowtype-rules)
+ * [`boolean-style`](#eslint-plugin-flowtype-rules-boolean-style)
+ * [`define-flow-type`](#eslint-plugin-flowtype-rules-define-flow-type)
+ * [`delimiter-dangle`](#eslint-plugin-flowtype-rules-delimiter-dangle)
+ * [`generic-spacing`](#eslint-plugin-flowtype-rules-generic-spacing)
+ * [`no-dupe-keys`](#eslint-plugin-flowtype-rules-no-dupe-keys)
+ * [`no-weak-types`](#eslint-plugin-flowtype-rules-no-weak-types)
+ * [`object-type-delimiter`](#eslint-plugin-flowtype-rules-object-type-delimiter)
+ * [`require-parameter-type`](#eslint-plugin-flowtype-rules-require-parameter-type)
+ * [`require-return-type`](#eslint-plugin-flowtype-rules-require-return-type)
+ * [`require-valid-file-annotation`](#eslint-plugin-flowtype-rules-require-valid-file-annotation)
+ * [`semi`](#eslint-plugin-flowtype-rules-semi)
+ * [`sort-keys`](#eslint-plugin-flowtype-rules-sort-keys)
+ * [`space-after-type-colon`](#eslint-plugin-flowtype-rules-space-after-type-colon)
+ * [`space-before-generic-bracket`](#eslint-plugin-flowtype-rules-space-before-generic-bracket)
+ * [`space-before-type-colon`](#eslint-plugin-flowtype-rules-space-before-type-colon)
+ * [`type-id-match`](#eslint-plugin-flowtype-rules-type-id-match)
+ * [`union-intersection-spacing`](#eslint-plugin-flowtype-rules-union-intersection-spacing)
+ * [`use-flow-type`](#eslint-plugin-flowtype-rules-use-flow-type)
+ * [`valid-syntax`](#eslint-plugin-flowtype-rules-valid-syntax)
+
+
+<a name="eslint-plugin-flowtype-installation"></a>
+## Installation
+
+1. Install [ESLint](https://www.github.com/eslint/eslint).
+1. Install [`babel-eslint`](https://github.com/babel/babel-eslint) parser (ESLint parser [does not support type annotations](https://github.com/eslint/eslint/issues/2157)).
+1. Install [`eslint-plugin-flowtype`](https://github.com/gajus/eslint-plugin-flowtype) plugin.
+
+<!-- -->
+
+```sh
+npm install eslint
+npm install babel-eslint
+npm install eslint-plugin-flowtype
+```
+
+<a name="eslint-plugin-flowtype-configuration"></a>
+## Configuration
+
+1. Set `parser` property to `babel-eslint`.
+1. Add `plugins` section and specify `eslint-plugin-flowtype` as a plugin.
+1. Enable rules.
+
+<!-- -->
+
+```json
+{
+ "parser": "babel-eslint",
+ "plugins": [
+ "flowtype"
+ ],
+ "rules": {
+ "flowtype/boolean-style": [
+ 2,
+ "boolean"
+ ],
+ "flowtype/define-flow-type": 1,
+ "flowtype/delimiter-dangle": [
+ 2,
+ "never"
+ ],
+ "flowtype/generic-spacing": [
+ 2,
+ "never"
+ ],
+ "flowtype/no-weak-types": 2,
+ "flowtype/object-type-delimiter": [
+ 2,
+ "comma"
+ ],
+ "flowtype/require-parameter-type": 2,
+ "flowtype/require-return-type": [
+ 2,
+ "always",
+ {
+ "annotateUndefined": "never"
+ }
+ ],
+ "flowtype/require-valid-file-annotation": 2,
+ "flowtype/semi": [
+ 2,
+ "always"
+ ],
+ "flowtype/space-after-type-colon": [
+ 2,
+ "always"
+ ],
+ "flowtype/space-before-generic-bracket": [
+ 2,
+ "never"
+ ],
+ "flowtype/space-before-type-colon": [
+ 2,
+ "never"
+ ],
+ "flowtype/type-id-match": [
+ 2,
+ "^([A-Z][a-z0-9]+)+Type$"
+ ],
+ "flowtype/union-intersection-spacing": [
+ 2,
+ "always"
+ ],
+ "flowtype/use-flow-type": 1,
+ "flowtype/valid-syntax": 1
+ },
+ "settings": {
+ "flowtype": {
+ "onlyFilesWithFlowAnnotation": false
+ }
+ }
+}
+```
+
+<a name="eslint-plugin-flowtype-configuration-shareable-configurations"></a>
+### Shareable configurations
+
+<a name="eslint-plugin-flowtype-configuration-shareable-configurations-recommended"></a>
+#### Recommended
+
+This plugin exports a [recommended configuration](./src/configs/recommended.json) that enforces Flow type good practices.
+
+To enable this configuration use the extends property in your `.eslintrc` config file:
+
+```json
+{
+ "extends": [
+ "plugin:flowtype/recommended"
+ ],
+ "plugins": [
+ "flowtype"
+ ]
+}
+```
+
+See [ESLint documentation](http://eslint.org/docs/user-guide/configuring#extending-configuration-files) for more information about extending configuration files.
+
+<a name="eslint-plugin-flowtype-settings"></a>
+## Settings
+
+<a name="eslint-plugin-flowtype-settings-onlyfileswithflowannotation"></a>
+### <code>onlyFilesWithFlowAnnotation</code>
+
+When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/docs/about-flow.html#gradual) in the first comment.
+
+```js
+{
+ "settings": {
+ "flowtype": {
+ "onlyFilesWithFlowAnnotation": true
+ }
+ }
+}
+```
+
+<a name="eslint-plugin-flowtype-rules"></a>
+## Rules
+
+<!-- Rules are sorted alphabetically. -->
+
+<a name="eslint-plugin-flowtype-rules-boolean-style"></a>
+### <code>boolean-style</code>
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces a particular style for boolean type annotations. This rule takes one argument.
+
+If it is `'boolean'` then a problem is raised when using `bool` instead of `boolean`.
+
+If it is `'bool'` then a problem is raised when using `boolean` instead of `bool`.
+
+The default value is `'boolean'`.
+
+The following patterns are considered problems:
+
+```js
+type X = bool
+// Message: Use "boolean", not "bool"
+
+// Options: ["boolean"]
+type X = bool
+// Message: Use "boolean", not "bool"
+
+// Options: ["bool"]
+type X = boolean
+// Message: Use "bool", not "boolean"
+```
+
+The following patterns are not considered problems:
+
+```js
+type X = boolean
+
+// Options: ["boolean"]
+type X = boolean
+
+// Options: ["bool"]
+type X = bool
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-define-flow-type"></a>
+### <code>define-flow-type</code>
+
+Marks Flow type identifiers as defined.
+
+Used to suppress [`no-undef`](http://eslint.org/docs/rules/no-undef) reporting of type identifiers.
+
+The following patterns are not considered problems:
+
+```js
+var a: AType
+// Additional rules: {"no-undef":2}
+
+var a: AType; var b: AType
+// Additional rules: {"no-undef":2}
+
+var a; (a: AType)
+// Additional rules: {"no-undef":2}
+
+var a: AType<BType>
+// Additional rules: {"no-undef":2}
+
+type A = AType
+// Additional rules: {"no-undef":2}
+
+function f(a: AType) {}
+// Additional rules: {"no-undef":2}
+
+function f(a: AType.a) {}
+// Additional rules: {"no-undef":2}
+
+function f(a: AType.a.b) {}
+// Additional rules: {"no-undef":2}
+
+function f(a): AType {}; var a: AType
+// Additional rules: {"no-undef":2}
+
+function f(a): AType {}
+// Additional rules: {"no-undef":2}
+
+class C { a: AType }
+// Additional rules: {"no-undef":2}
+
+class C { a: AType.a }
+// Additional rules: {"no-undef":2}
+
+class C { a: AType.a.b }
+// Additional rules: {"no-undef":2}
+
+class C implements AType {}
+// Additional rules: {"no-undef":2}
+
+interface AType {}
+// Additional rules: {"no-undef":2}
+
+({ a: ({b() {}}: AType) })
+// Additional rules: {"no-undef":2}
+
+type X = {Y<AType>(): BType}
+// Additional rules: {"no-undef":2}
+
+interface AType<BType> {}
+// Additional rules: {"no-undef":2}
+
+var a: AType
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+var a: AType; var b: AType
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+var a; (a: AType)
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+var a: AType<BType>
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+type A = AType
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+function f(a: AType) {}
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+function f(a: AType.a) {}
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+function f(a: AType.a.b) {}
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+function f(a): AType {}; var a: AType
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+function f(a): AType {}
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+class C { a: AType }
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+class C { a: AType.a }
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+class C { a: AType.a.b }
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+class C implements AType {}
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+interface AType {}
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+({ a: ({b() {}}: AType) })
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+type X = {Y<AType>(): BType}
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+
+interface AType<BType> {}
+// Additional rules: {"no-undef":2,"no-use-before-define":[2,"nofunc"]}
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-delimiter-dangle"></a>
+### <code>delimiter-dangle</code>
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent use of trailing commas in Object and Tuple annotations.
+
+This rule takes one argument which mirrors ESLint's default `comma-dangle` rule.
+
+If it is `'never'` then a problem is raised when there is a trailing comma.
+
+If it is `'always'` then a problem is raised when there is no trailing comma.
+
+If it is `'always-multiline'` then a problem is raised when there is no trailing comma on a multi-line definition, or there _is_ a trailing comma on a single-line definition.
+
+If it is `'only-multiline'` then a problem is raised when there is a trailing comma on a single-line definition. It allows, but does not enforce, trailing commas on multi-line definitions.
+
+The default value is `'never'`.
+
+The following patterns are considered problems:
+
+```js
+type X = { foo: string, }
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = { foo: string, }
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = { foo: string; }
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = {
+foo: string,
+}
+// Message: Unexpected trailing delimiter
+
+// Options: ["always"]
+type X = { foo: string }
+// Message: Missing trailing delimiter
+
+// Options: ["always"]
+type X = {
+foo: string
+}
+// Message: Missing trailing delimiter
+
+// Options: ["always-multiline"]
+type X = { foo: string, }
+// Message: Unexpected trailing delimiter
+
+// Options: ["always-multiline"]
+type X = {
+foo: string
+}
+// Message: Missing trailing delimiter
+
+// Options: ["only-multiline"]
+type X = { foo: string; }
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = { [key: string]: number, }
+// Message: Unexpected trailing delimiter
+
+// Options: ["always"]
+type X = { [key: string]: number }
+// Message: Missing trailing delimiter
+
+// Options: ["always-multiline"]
+type X = { [key: string]: number, }
+// Message: Unexpected trailing delimiter
+
+// Options: ["always-multiline"]
+type X = {
+[key: string]: number
+}
+// Message: Missing trailing delimiter
+
+// Options: ["only-multiline"]
+type X = { [key: string]: number; }
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = { [key: string]: number, foo: string, }
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = {
+[key: string]: number,
+foo: string,
+}
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = {
+[key: string]: number,
+aReallyLongPropertyNameHere: string,
+}
+// Message: Unexpected trailing delimiter
+
+// Options: ["always"]
+type X = { [key: string]: number, foo: string }
+// Message: Missing trailing delimiter
+
+// Options: ["always"]
+type X = {
+[key: string]: number;
+foo: string
+}
+// Message: Missing trailing delimiter
+
+// Options: ["always-multiline"]
+type X = { [key: string]: number, foo: string, }
+// Message: Unexpected trailing delimiter
+
+// Options: ["always-multiline"]
+type X = {
+[key: string]: number,
+foo: string
+}
+// Message: Missing trailing delimiter
+
+// Options: ["only-multiline"]
+type X = { [key: string]: number, foo: string, }
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = { foo: string, [key: string]: number, }
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = {
+foo: string,
+[key: string]: number,
+}
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = {
+aReallyLongPropertyNameHere: string,
+[key: string]: number,
+}
+// Message: Unexpected trailing delimiter
+
+// Options: ["always"]
+type X = { foo: string, [key: string]: number }
+// Message: Missing trailing delimiter
+
+// Options: ["always"]
+type X = { foo: string; [key: string]: number }
+// Message: Missing trailing delimiter
+
+// Options: ["always-multiline"]
+type X = { foo: string, [key: string]: number; }
+// Message: Unexpected trailing delimiter
+
+// Options: ["always-multiline"]
+type X = {
+foo: string,
+[key: string]: number
+}
+// Message: Missing trailing delimiter
+
+// Options: ["only-multiline"]
+type X = { foo: string, [key: string]: number; }
+// Message: Unexpected trailing delimiter
+
+type X = [string, number,]
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = [string, number,]
+// Message: Unexpected trailing delimiter
+
+// Options: ["never"]
+type X = [
+string,
+number,
+]
+// Message: Unexpected trailing delimiter
+
+// Options: ["always"]
+type X = [string, number]
+// Message: Missing trailing delimiter
+
+// Options: ["always"]
+type X = [
+string,
+number
+]
+// Message: Missing trailing delimiter
+
+// Options: ["always-multiline"]
+type X = [string, number,]
+// Message: Unexpected trailing delimiter
+
+// Options: ["always-multiline"]
+type X = [
+foo, string
+]
+// Message: Missing trailing delimiter
+
+// Options: ["only-multiline"]
+type X = [ number, string, ]
+// Message: Unexpected trailing delimiter
+```
+
+The following patterns are not considered problems:
+
+```js
+type X = { foo: string }
+
+// Options: ["never"]
+type X = { foo: string }
+
+// Options: ["always"]
+type X = { foo: string, }
+
+// Options: ["always"]
+type X = { foo: string; }
+
+// Options: ["never"]
+type X = {
+foo: string
+}
+
+// Options: ["always"]
+type X = {
+foo: string,
+}
+
+// Options: ["always-multiline"]
+type X = { foo: string }
+
+// Options: ["always-multiline"]
+type X = {
+foo: string,
+}
+
+// Options: ["always-multiline"]
+type X = {
+foo: string;
+}
+
+// Options: ["only-multiline"]
+type X = { foo: string }
+
+// Options: ["only-multiline"]
+type X = {
+foo: string
+}
+
+// Options: ["only-multiline"]
+type X = {
+foo: string,
+}
+
+// Options: ["only-multiline"]
+type X = {
+foo: string;
+}
+
+// Options: ["never"]
+type X = {}
+
+// Options: ["always"]
+type X = {}
+
+// Options: ["always-multiline"]
+type X = {}
+
+// Options: ["only-multiline"]
+type X = {}
+
+// Options: ["never"]
+type X = { [key: string]: number }
+
+// Options: ["always"]
+type X = { [key: string]: number, }
+
+// Options: ["always"]
+type X = { [key: string]: number; }
+
+// Options: ["always-multiline"]
+type X = { [key: string]: number }
+
+// Options: ["always-multiline"]
+type X = {
+[key: string]: number,
+}
+
+// Options: ["only-multiline"]
+type X = {
+[key: string]: number,
+}
+
+// Options: ["only-multiline"]
+type X = {
+[key: string]: number
+}
+
+// Options: ["only-multiline"]
+type X = { [key: string]: number }
+
+// Options: ["never"]
+type X = { [key: string]: number, foo: string }
+
+// Options: ["always"]
+type X = { [key: string]: number, foo: string, }
+
+// Options: ["always"]
+type X = { [key: string]: number; foo: string; }
+
+// Options: ["always-multiline"]
+type X = { [key: string]: number, foo: string }
+
+// Options: ["always-multiline"]
+type X = {
+[key: string]: number,
+foo: string,
+}
+
+// Options: ["only-multiline"]
+type X = {
+[key: string]: number,
+foo: string,
+}
+
+// Options: ["only-multiline"]
+type X = {
+[key: string]: number;
+foo: string
+}
+
+// Options: ["only-multiline"]
+type X = { [key: string]: number, foo: string }
+
+// Options: ["never"]
+type X = { foo: string, [key: string]: number }
+
+// Options: ["always"]
+type X = { foo: string, [key: string]: number, }
+
+// Options: ["always"]
+type X = { foo: string; [key: string]: number; }
+
+// Options: ["always-multiline"]
+type X = { foo: string, [key: string]: number }
+
+// Options: ["always-multiline"]
+type X = {
+foo: string,
+[key: string]: number,
+}
+
+// Options: ["only-multiline"]
+type X = {
+foo: string,
+[key: string]: number,
+}
+
+// Options: ["only-multiline"]
+type X = {
+foo: string;
+[key: string]: number
+}
+
+// Options: ["only-multiline"]
+type X = { foo: string, [key: string]: number }
+
+type X = [string, number]
+
+// Options: ["never"]
+type X = [string, number]
+
+// Options: ["never"]
+type X = [
+string,
+number
+]
+
+// Options: ["always"]
+type X = [string, number,]
+
+// Options: ["always"]
+type X = [
+string,
+number,
+]
+
+// Options: ["always-multiline"]
+type X = [ foo, string ]
+
+// Options: ["always-multiline"]
+type X = [
+foo, string,
+]
+
+// Options: ["only-multiline"]
+type X = [ number, string ]
+
+// Options: ["only-multiline"]
+type X = [
+number,
+string
+]
+
+// Options: ["only-multiline"]
+type X = [
+number,
+string,
+]
+
+// Options: ["never"]
+type X = []
+
+// Options: ["always"]
+type X = []
+
+// Options: ["always-multiline"]
+type X = []
+
+// Options: ["only-multiline"]
+type X = []
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-generic-spacing"></a>
+### <code>generic-spacing</code>
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing within generic type annotation parameters.
+
+This rule takes one argument. If it is `'never'` then a problem is raised when there is a space surrounding the generic type parameters. If it is `'always'` then a problem is raised when there is no space surrounding the generic type parameters.
+
+The default value is `'never'`.
+
+The following patterns are considered problems:
+
+```js
+type X = Promise< string>
+// Message: There must be no space at start of "Promise" generic type annotation
+
+// Options: ["never"]
+type X = Promise< string>
+// Message: There must be no space at start of "Promise" generic type annotation
+
+type X = FooBar<string >
+// Message: There must be no space at end of "FooBar" generic type annotation
+
+type X = Promise< string >
+// Message: There must be no space at start of "Promise" generic type annotation
+// Message: There must be no space at end of "Promise" generic type annotation
+
+type X = Promise< (foo), bar, (((baz))) >
+// Message: There must be no space at start of "Promise" generic type annotation
+// Message: There must be no space at end of "Promise" generic type annotation
+
+// Options: ["always"]
+type X = Promise<string >
+// Message: There must be a space at start of "Promise" generic type annotation
+
+// Options: ["always"]
+type X = FooBar< string>
+// Message: There must be a space at end of "FooBar" generic type annotation
+
+// Options: ["always"]
+type X = Promise<string>
+// Message: There must be a space at start of "Promise" generic type annotation
+// Message: There must be a space at end of "Promise" generic type annotation
+
+// Options: ["always"]
+type X = Promise<(foo), bar, (((baz)))>
+// Message: There must be a space at start of "Promise" generic type annotation
+// Message: There must be a space at end of "Promise" generic type annotation
+
+// Options: ["always"]
+type X = FooBar< string >
+// Message: There must be one space at start of "FooBar" generic type annotation
+
+// Options: ["always"]
+type X = FooBar< string >
+// Message: There must be one space at end of "FooBar" generic type annotation
+
+// Options: ["always"]
+type X = Promise< (foo), bar, (((baz))) >
+// Message: There must be one space at start of "Promise" generic type annotation
+// Message: There must be one space at end of "Promise" generic type annotation
+```
+
+The following patterns are not considered problems:
+
+```js
+type X = Promise<string>
+
+type X = Promise<(string)>
+
+type X = Promise<(foo), bar, (((baz)))>
+
+// Options: ["always"]
+type X = Promise< string >
+
+// Options: ["always"]
+type X = Promise< (string) >
+
+// Options: ["always"]
+type X = Promise< (foo), bar, (((baz))) >
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-no-dupe-keys"></a>
+### <code>no-dupe-keys</code>
+
+Checks for duplicate properties in Object annotations.
+
+This rule mirrors ESLint's [no-dupe-keys](http://eslint.org/docs/rules/no-dupe-keys) rule.
+
+```js
+{
+ "rules": {
+ "flowtype/no-dupe-keys": 2
+ }
+}
+```
+
+The following patterns are considered problems:
+
+```js
+type FooType = { a: number, b: string, a: number }
+// Message: Duplicate property.
+
+type FooType = { a: number, b: string, a: string }
+// Message: Duplicate property.
+```
+
+The following patterns are not considered problems:
+
+```js
+type FooType = { a: number, b: string, c: number }
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-no-weak-types"></a>
+### <code>no-weak-types</code>
+
+Warns against weak type annotations *any*, *Object* and *Function*.
+These types can cause flow to silently skip over portions of your code,
+which would have otherwise caused type errors.
+
+This rule optionally takes one argument, an object to configure which type warnings to enable. By default, all of the
+warnings are enabled. e.g. to disable the `any` warning (allowing it to exist in your code), while continuing to warn
+about `Object` and `Function`:
+
+```js
+{
+ "rules": {
+ "flowtype/no-weak-types": [2, {
+ "any": false,
+ "Object": true,
+ "Function": true
+ }]
+ }
+}
+
+// or, the following is equivalent as default is true:
+
+{
+ "rules": {
+ "flowtype/no-weak-types": [2, {
+ "any": false
+ }]
+ }
+}
+```
+
+The following patterns are considered problems:
+
+```js
+function foo(thing): any {}
+// Message: Unexpected use of weak type "any"
+
+function foo(thing): Promise<any> {}
+// Message: Unexpected use of weak type "any"
+
+function foo(thing): Promise<Promise<any>> {}
+// Message: Unexpected use of weak type "any"
+
+function foo(thing): Object {}
+// Message: Unexpected use of weak type "Object"
+
+function foo(thing): Promise<Object> {}
+// Message: Unexpected use of weak type "Object"
+
+function foo(thing): Promise<Promise<Object>> {}
+// Message: Unexpected use of weak type "Object"
+
+function foo(thing): Function {}
+// Message: Unexpected use of weak type "Function"
+
+function foo(thing): Promise<Function> {}
+// Message: Unexpected use of weak type "Function"
+
+function foo(thing): Promise<Promise<Function>> {}
+// Message: Unexpected use of weak type "Function"
+
+(foo: any) => {}
+// Message: Unexpected use of weak type "any"
+
+(foo: Function) => {}
+// Message: Unexpected use of weak type "Function"
+
+(foo?: any) => {}
+// Message: Unexpected use of weak type "any"
+
+(foo?: Function) => {}
+// Message: Unexpected use of weak type "Function"
+
+(foo: { a: any }) => {}
+// Message: Unexpected use of weak type "any"
+
+(foo: { a: Object }) => {}
+// Message: Unexpected use of weak type "Object"
+
+(foo: any[]) => {}
+// Message: Unexpected use of weak type "any"
+
+type Foo = any
+// Message: Unexpected use of weak type "any"
+
+type Foo = Function
+// Message: Unexpected use of weak type "Function"
+
+type Foo = { a: any }
+// Message: Unexpected use of weak type "any"
+
+type Foo = { a: Object }
+// Message: Unexpected use of weak type "Object"
+
+type Foo = { (a: Object): string }
+// Message: Unexpected use of weak type "Object"
+
+type Foo = { (a: string): Function }
+// Message: Unexpected use of weak type "Function"
+
+function foo(thing: any) {}
+// Message: Unexpected use of weak type "any"
+
+function foo(thing: Object) {}
+// Message: Unexpected use of weak type "Object"
+
+var foo: Function
+// Message: Unexpected use of weak type "Function"
+
+var foo: Object
+// Message: Unexpected use of weak type "Object"
+
+class Foo { props: any }
+// Message: Unexpected use of weak type "any"
+
+class Foo { props: Object }
+// Message: Unexpected use of weak type "Object"
+
+var foo: any
+// Message: Unexpected use of weak type "any"
+
+// Options: [{"Function":false}]
+type X = any; type Y = Function; type Z = Object
+// Message: Unexpected use of weak type "any"
+// Message: Unexpected use of weak type "Object"
+
+// Options: [{"Object":false,"any":false}]
+type X = any; type Y = Function; type Z = Object
+// Message: Unexpected use of weak type "Function"
+```
+
+The following patterns are not considered problems:
+
+```js
+function foo(thing): string {}
+
+function foo(thing): Promise<string> {}
+
+function foo(thing): Promise<Promise<string>> {}
+
+(foo?: string) => {}
+
+(foo: ?string) => {}
+
+(foo: { a: string }) => {}
+
+(foo: { a: ?string }) => {}
+
+(foo: string[]) => {}
+
+type Foo = string
+
+type Foo = { a: string }
+
+type Foo = { (a: string): string }
+
+function foo(thing: string) {}
+
+var foo: string
+
+class Foo { props: string }
+
+// Options: [{"Object":false,"any":false}]
+type X = any; type Y = Object
+
+// Options: [{"Function":false}]
+type X = Function
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-object-type-delimiter"></a>
+### <code>object-type-delimiter</code>
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent separators between properties in Flow object types.
+
+This rule takes one argument.
+
+If it is `'comma'` then a problem is raised when using `;` as a separator.
+
+If it is `'semicolon'` then a problem is raised when using `,` as a separator.
+
+The default value is `'comma'`.
+
+_This rule is ported from `babel/flow-object-type`, however the default option was changed._
+
+The following patterns are considered problems:
+
+```js
+// Options: ["semicolon"]
+type Foo = { a: Foo, b: Bar }
+// Message: Prefer semicolons to commas in object and class types
+
+// Options: ["comma"]
+type Foo = { a: Foo; b: Bar }
+// Message: Prefer commas to semicolons in object and class types
+
+// Options: ["semicolon"]
+type Foo = { [a: string]: Foo, [b: string]: Bar }
+// Message: Prefer semicolons to commas in object and class types
+
+// Options: ["comma"]
+type Foo = { [a: string]: Foo; [b: string]: Bar }
+// Message: Prefer commas to semicolons in object and class types
+
+// Options: ["semicolon"]
+type Foo = { (): Foo, (): Bar }
+// Message: Prefer semicolons to commas in object and class types
+
+// Options: ["comma"]
+type Foo = { (): Foo; (): Bar }
+// Message: Prefer commas to semicolons in object and class types
+
+// Options: ["semicolon"]
+declare class Foo { a: Foo, }
+// Message: Prefer semicolons to commas in object and class types
+
+// Options: ["comma"]
+declare class Foo { a: Foo; }
+// Message: Prefer commas to semicolons in object and class types
+
+// Options: ["semicolon"]
+declare class Foo { [a: string]: Foo, }
+// Message: Prefer semicolons to commas in object and class types
+
+// Options: ["comma"]
+declare class Foo { a: Foo; }
+// Message: Prefer commas to semicolons in object and class types
+
+// Options: ["semicolon"]
+declare class Foo { (): Foo, }
+// Message: Prefer semicolons to commas in object and class types
+
+// Options: ["comma"]
+declare class Foo { (): Foo; }
+// Message: Prefer commas to semicolons in object and class types
+
+// Options: ["semicolon"]
+declare class Foo { static (): Foo, }
+// Message: Prefer semicolons to commas in object and class types
+
+// Options: ["comma"]
+declare class Foo { static (): Foo; }
+// Message: Prefer commas to semicolons in object and class types
+```
+
+The following patterns are not considered problems:
+
+```js
+// Options: ["semicolon"]
+type Foo = { a: Foo; b: Bar }
+
+// Options: ["comma"]
+type Foo = { a: Foo, b: Bar }
+
+// Options: ["semicolon"]
+type Foo = { [a: string]: Foo; [b: string]: Bar }
+
+// Options: ["comma"]
+type Foo = { [a: string]: Foo, [b: string]: Bar }
+
+// Options: ["semicolon"]
+type Foo = { (): Foo; (): Bar }
+
+// Options: ["comma"]
+type Foo = { (): Foo, (): Bar }
+
+type Foo = { a: Foo, b: Bar }
+
+type Foo = { [a: string]: Foo, [b: string]: Bar }
+
+type Foo = { (): Foo, (): Bar }
+
+// Options: ["semicolon"]
+declare class Foo { a: Foo; }
+
+// Options: ["comma"]
+declare class Foo { a: Foo, }
+
+// Options: ["semicolon"]
+declare class Foo { [a: string]: Foo; }
+
+// Options: ["comma"]
+declare class Foo { [a: string]: Foo, }
+
+// Options: ["semicolon"]
+declare class Foo { (): Foo; }
+
+// Options: ["comma"]
+declare class Foo { (): Foo, }
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-require-parameter-type"></a>
+### <code>require-parameter-type</code>
+
+Requires that all function parameters have type annotations.
+
+<a name="eslint-plugin-flowtype-rules-require-parameter-type-options"></a>
+#### Options
+
+You can skip all arrow functions by providing the `excludeArrowFunctions` option with `true`.
+
+Alternatively, you can want to exclude only concise arrow functions (e.g. `x => x * 2`). Provide `excludeArrowFunctions` with `expressionsOnly` for this.
+
+```js
+{
+ "rules": {
+ "flowtype/require-parameter-type": [
+ 2,
+ {
+ "excludeArrowFunctions": true
+ }
+ ]
+ }
+}
+
+{
+ "rules": {
+ "flowtype/require-parameter-type": [
+ 2,
+ {
+ "excludeArrowFunctions": "expressionsOnly"
+ }
+ ]
+ }
+}
+```
+
+You can exclude parameters that match a certain regex by using `excludeParameterMatch`.
+
+```js
+{
+ "rules": {
+ "flowtype/require-parameter-type": [
+ 2,
+ {
+ "excludeParameterMatch": "^_"
+ }
+ ]
+ }
+}
+```
+
+This excludes all parameters that start with an underscore (`_`).
+The default pattern is `a^`, which doesn't match anything, i.e., all parameters are checked.
+
+The following patterns are considered problems:
+
+```js
+(foo) => {}
+// Message: Missing "foo" parameter type annotation.
+
+function x(foo) {}
+// Message: Missing "foo" parameter type annotation.
+
+// Options: [{"excludeArrowFunctions":true}]
+function x(foo) {}
+// Message: Missing "foo" parameter type annotation.
+
+(foo = 'FOO') => {}
+// Message: Missing "foo" parameter type annotation.
+
+(...foo) => {}
+// Message: Missing "foo" parameter type annotation.
+
+({foo}) => {}
+// Message: Missing "{foo}" parameter type annotation.
+
+([foo]) => {}
+// Message: Missing "[foo]" parameter type annotation.
+
+({foo = 1} = {}) => {}
+// Message: Missing "{foo = 1}" parameter type annotation.
+
+// @flow
+(foo) => {}
+// Message: Missing "foo" parameter type annotation.
+
+// Options: [{"excludeArrowFunctions":"expressionsOnly"}]
+(foo) => {}
+// Message: Missing "foo" parameter type annotation.
+
+// Options: [{"excludeArrowFunctions":"expressionsOnly"}]
+function x(foo) {}
+// Message: Missing "foo" parameter type annotation.
+
+// Options: [{"excludeParameterMatch":"^_"}]
+(_foo: number, bar) => {}
+// Message: Missing "bar" parameter type annotation.
+
+// Options: [{"excludeParameterMatch":"^_"}]
+(_foo, bar) => {}
+// Message: Missing "bar" parameter type annotation.
+```
+
+The following patterns are not considered problems:
+
+```js
+(foo: string) => {}
+
+(foo: string = 'FOO') => {}
+
+(...foo: string) => {}
+
+({foo}: {foo: string}) => {}
+
+([foo]: Array) => {}
+
+(foo) => {}
+
+// Options: [{"excludeArrowFunctions":true}]
+(foo) => {}
+
+// Options: [{"excludeArrowFunctions":"expressionsOnly"}]
+(foo) => 3
+
+// Options: [{"excludeParameterMatch":"^_"}]
+(_foo, bar: string) => {}
+
+// Options: [{"excludeParameterMatch":"^_"}]
+(_foo: number, bar: string) => {}
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-require-return-type"></a>
+### <code>require-return-type</code>
+
+Requires that functions have return type annotation.
+
+<a name="eslint-plugin-flowtype-rules-require-return-type-options"></a>
+#### Options
+
+You can skip all arrow functions by providing the `excludeArrowFunctions` option with `true`.
+
+Alternatively, you can want to exclude only concise arrow function (e.g. `() => 2`). Provide `excludeArrowFunctions` with `expressionsOnly` for this.
+
+```js
+{
+ "rules": {
+ "flowtype/require-return-type": [
+ 2,
+ "always",
+ {
+ "excludeArrowFunctions": true
+ }
+ ]
+ }
+}
+
+{
+ "rules": {
+ "flowtype/require-return-type": [
+ 2,
+ "always",
+ {
+ "excludeArrowFunctions": "expressionsOnly"
+ }
+ ]
+ }
+}
+```
+
+The following patterns are considered problems:
+
+```js
+(foo) => { return "foo"; }
+// Message: Missing return type annotation.
+
+// Options: ["always"]
+(foo) => { return "foo"; }
+// Message: Missing return type annotation.
+
+// Options: ["always"]
+(foo) => "foo"
+// Message: Missing return type annotation.
+
+(foo) => ({})
+// Message: Missing return type annotation.
+
+(foo): undefined => { return; }
+// Message: Must not annotate undefined return type.
+
+(foo): void => { return; }
+// Message: Must not annotate undefined return type.
+
+(foo): undefined => { return undefined; }
+// Message: Must not annotate undefined return type.
+
+(foo): void => { return void 0; }
+// Message: Must not annotate undefined return type.
+
+// Options: ["always",{"annotateUndefined":"never"}]
+(foo): undefined => { return; }
+// Message: Must not annotate undefined return type.
+
+// Options: ["always",{"annotateUndefined":"never"}]
+(foo): void => { return; }
+// Message: Must not annotate undefined return type.
+
+// Options: ["always",{"annotateUndefined":"always"}]
+(foo) => { return; }
+// Message: Must annotate undefined return type.
+
+// Options: ["always",{"annotateUndefined":"never"}]
+(foo): undefined => { return undefined; }
+// Message: Must not annotate undefined return type.
+
+// Options: ["always",{"annotateUndefined":"always"}]
+(foo) => { return undefined; }
+// Message: Must annotate undefined return type.
+
+// Options: ["always",{"annotateUndefined":"always"}]
+(foo) => { return void 0; }
+// Message: Must annotate undefined return type.
+
+// @flow
+(foo) => { return 1; }
+// Message: Missing return type annotation.
+
+// Options: ["always",{"annotateUndefined":"always"}]
+// @flow
+ (foo) => { return undefined; }
+// Message: Must annotate undefined return type.
+
+// Options: ["always"]
+async () => { return 2; }
+// Message: Missing return type annotation.
+
+// Options: ["always",{"annotateUndefined":"always"}]
+async () => {}
+// Message: Missing return type annotation.
+
+// Options: ["always",{"annotateUndefined":"always"}]
+async function x() {}
+// Message: Missing return type annotation.
+
+// Options: ["always"]
+async () => { return; }
+// Message: Missing return type annotation.
+
+// Options: ["always"]
+function* x() {}
+// Message: Missing return type annotation.
+
+// Options: ["always",{"excludeArrowFunctions":"expressionsOnly"}]
+() => { return 3; }
+// Message: Missing return type annotation.
+
+// Options: ["always",{"excludeArrowFunctions":"expressionsOnly"}]
+async () => { return 4; }
+// Message: Missing return type annotation.
+```
+
+The following patterns are not considered problems:
+
+```js
+(foo): string => {}
+
+// Options: ["always"]
+(foo): string => {}
+
+(foo) => { return; }
+
+(foo): Object => ( {} )
+
+(foo) => { return undefined; }
+
+(foo) => { return void 0; }
+
+// Options: ["always",{"annotateUndefined":"always"}]
+(foo): undefined => { return; }
+
+// Options: ["always",{"annotateUndefined":"always"}]
+(foo): void => { return; }
+
+// Options: ["always",{"annotateUndefined":"never"}]
+(foo) => { return; }
+
+// Options: ["always",{"annotateUndefined":"never"}]
+(foo) => { return undefined; }
+
+// Options: ["always",{"annotateUndefined":"never"}]
+(foo) => { return void 0; }
+
+// Options: ["always",{"annotateUndefined":"always"}]
+(foo): undefined => { return undefined; }
+
+// Options: ["always",{"annotateUndefined":"always"}]
+(foo): void => { return void 0; }
+
+// Options: ["always"]
+(foo) => { return 1; }
+
+// Options: ["always",{"annotateUndefined":"always"}]
+(foo) => { return undefined; }
+
+// Options: ["always",{"annotateUndefined":"always"}]
+async function doThing(): Promise<void> {}
+
+// Options: ["always",{"annotateUndefined":"always"}]
+function* doThing(): Generator<number, void, void> { yield 2; }
+
+async (foo): Promise<number> => { return 3; }
+
+// Options: ["always",{"excludeArrowFunctions":true}]
+() => 3
+
+// Options: ["always",{"excludeArrowFunctions":true}]
+() => { return 4; }
+
+// Options: ["always",{"excludeArrowFunctions":true}]
+() => undefined
+
+// Options: ["always",{"annotateUndefined":"always","excludeArrowFunctions":true}]
+() => undefined
+
+// Options: ["always",{"annotateUndefined":"always","excludeArrowFunctions":true}]
+() => { return undefined; }
+
+// Options: ["always",{"excludeArrowFunctions":"expressionsOnly"}]
+() => 3
+
+// Options: ["always",{"excludeArrowFunctions":"expressionsOnly"}]
+async () => 3
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-require-valid-file-annotation"></a>
+### <code>require-valid-file-annotation</code>
+
+This rule validates Flow file annotations.
+
+This rule can optionally report missing or missed placed annotations, common typos (e.g. `// @floww`), and enforce a consistant annotation style.
+
+<a name="eslint-plugin-flowtype-rules-require-valid-file-annotation-options"></a>
+#### Options
+
+The rule has a string option:
+
+* `"never"` (default): Never report files that are missing an `@flow` annotation.
+* `"always"`: Always report files that are missing an `@flow` annotation
+
+This rule has an object option:
+
+* `"annotationStyle"` - Enforce a consistant file annotation style.
+ * `"none"` (default): Either annotation style is accepted.
+ * `"line"`: Require single line annotations (i.e. `// @flow`).
+ * `"block"`: Require block annotations (i.e. `/* @flow */`).
+
+```js
+{
+ "rules": {
+ "flowtype/require-valid-file-annotation": [
+ 2,
+ "always"
+ ]
+ }
+}
+
+{
+ "rules": {
+ "flowtype/require-valid-file-annotation": [
+ 2,
+ "always", {
+ "annotationStyle": "block"
+ }
+ ]
+ }
+}
+```
+
+The following patterns are considered problems:
+
+```js
+;// @flow
+// Message: Flow file annotation not at the top of the file.
+
+;
+// @flow
+// Message: Flow file annotation not at the top of the file.
+
+// @Flow
+// Message: Malformed flow file annotation.
+
+// @floweeeeeee
+// Message: Malformed flow file annotation.
+
+// @NoFlow
+// Message: Malformed flow file annotation.
+
+// @nofloweeeeeee
+// Message: Malformed flow file annotation.
+
+// Options: ["always"]
+a;
+// Message: Flow file annotation is missing.
+
+// Options: ["always",{"annotationStyle":"line"}]
+/* @flow */
+// Message: Flow file annotation style must be `// @flow`
+
+// Options: ["always",{"annotationStyle":"block"}]
+// @flow
+// Message: Flow file annotation style must be `/* @flow */`
+```
+
+The following patterns are not considered problems:
+
+```js
+a;
+
+// @flow
+a;
+
+//@flow
+a;
+
+//**@flow
+a;
+
+/* foo @flow bar */
+a;
+
+
+
+// @flow
+a;
+
+// @flow
+// @FLow
+
+// @noflow
+a;
+
+// Options: ["always"]
+a;
+
+// Options: ["always",{"annotationStyle":"line"}]
+// @flow
+
+// Options: ["always",{"annotationStyle":"block"}]
+/* @flow */
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-semi"></a>
+### <code>semi</code>
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent use of semicolons after type aliases.
+
+This rule takes one argument. If it is `'never'` then a problem is raised when there is a semicolon after a type alias. If it is `'always'` then a problem is raised when there is no semicolon after a type alias.
+
+The default value is `'always'`.
+
+The following patterns are considered problems:
+
+```js
+// Options: []
+type FooType = {}
+// Message: Missing semicolon.
+
+// Options: ["always"]
+type FooType = {}
+// Message: Missing semicolon.
+
+// Options: ["never"]
+type FooType = {};
+// Message: Extra semicolon.
+```
+
+The following patterns are not considered problems:
+
+```js
+type FooType = {};
+
+// Options: ["always"]
+type FooType = {};
+
+// Options: ["always"]
+type FooType = { a: number;
+ b: string;
+ };
+
+// Options: ["never"]
+type FooType = { a: number;
+ b: string;
+ }
+
+// Options: ["never"]
+type FooType = {}
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-sort-keys"></a>
+### <code>sort-keys</code>
+
+Enforces sorting of Object annotations.
+
+This rule mirrors ESlint's [sort-keys](http://eslint.org/docs/rules/sort-keys) rule.
+
+<a name="eslint-plugin-flowtype-rules-sort-keys-options"></a>
+#### Options
+
+The first option specifies sort order.
+
+* `"asc"` (default) - enforce ascending sort order.
+* `"desc"` - enforce descending sort order.
+
+The second option takes an object with two possible properties.
+
+* `caseSensitive` - if `true`, enforce case-sensitive sort order. Default is `true`.
+* `natural` - if `true`, enforce [natural sort order](https://en.wikipedia.org/wiki/Natural_sort_order). Default is `false`.
+
+```js
+{
+ "rules": {
+ "flowtype/sort-keys": [
+ 2,
+ "asc", {
+ "caseSensitive": true,
+ "natural": false
+ }
+ ]
+ }
+}
+```
+
+The following patterns are considered problems:
+
+```js
+type FooType = { a: number, c: number, b: string }
+// Message: Expected type annotations to be in ascending order. "b" should be before "c".
+
+type FooType = { a: number, b: number, C: number }
+// Message: Expected type annotations to be in ascending order. "C" should be before "b".
+
+type FooType = { 1: number, 2: number, 10: number }
+// Message: Expected type annotations to be in ascending order. "10" should be before "2".
+
+// Options: ["desc"]
+type FooType = { a: number, b: number }
+// Message: Expected type annotations to be in descending order. "b" should be before "a".
+
+// Options: ["desc"]
+type FooType = { C: number, b: number, a: string }
+// Message: Expected type annotations to be in descending order. "b" should be before "C".
+
+// Options: ["desc"]
+type FooType = { 10: number, 2: number, 1: number }
+// Message: Expected type annotations to be in descending order. "2" should be before "10".
+
+// Options: ["asc",{"caseSensitive":false}]
+type FooType = { a: number, c: number, C: number, b: string }
+// Message: Expected type annotations to be in insensitive ascending order. "b" should be before "C".
+
+// Options: ["asc",{"caseSensitive":false}]
+type FooType = { a: number, C: number, c: number, b: string }
+// Message: Expected type annotations to be in insensitive ascending order. "b" should be before "c".
+
+// Options: ["asc",{"natural":true}]
+type FooType = { 1: number, 10: number, 2: boolean }
+// Message: Expected type annotations to be in natural ascending order. "2" should be before "10".
+```
+
+The following patterns are not considered problems:
+
+```js
+type FooType = { a: number }
+
+type FooType = { a: number, b: number, c: (boolean | number) }
+
+type FooType = { C: number, a: string, b: foo }
+
+type FooType = { 1: number, 10: number, 2: boolean }
+
+// Options: ["desc"]
+type FooType = { c: number, b: number, a: number }
+
+// Options: ["desc"]
+type FooType = { b: string, a: {}, C: number }
+
+// Options: ["desc"]
+type FooType = { 2: number, 10: number, 1: boolean }
+
+// Options: ["asc",{"caseSensitive":false}]
+type FooType = { a: number, b: number, c: number, C: number }
+
+// Options: ["asc",{"caseSensitive":false}]
+type FooType = { a: number, b: number, C: number, c: number }
+
+// Options: ["asc",{"natural":true}]
+type FooType = { 1:number, 2: number, 10: number }
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-space-after-type-colon"></a>
+### <code>space-after-type-colon</code>
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing after the type annotation colon.
+
+This rule takes one argument. If it is `'always'` then a problem is raised when there is no space after the type annotation colon. If it is `'never'` then a problem is raised when there is a space after the type annotation colon. The default value is `'always'`.
+
+The following patterns are considered problems:
+
+```js
+// Options: ["never"]
+(foo: string) => {}
+// Message: There must be no space after "foo" parameter type annotation colon.
+
+// Options: ["always"]
+(foo: string) => {}
+// Message: There must be 1 space after "foo" parameter type annotation colon.
+
+// Options: ["always"]
+(foo:(() => void)) => {}
+// Message: There must be a space after "foo" parameter type annotation colon.
+
+// Options: ["never"]
+(foo: (() => void)) => {}
+// Message: There must be no space after "foo" parameter type annotation colon.
+
+// Options: ["always"]
+(foo: (() => void)) => {}
+// Message: There must be 1 space after "foo" parameter type annotation colon.
+
+({ lorem, ipsum, dolor } : SomeType) => {}
+// Message: There must be 1 space after "{ lorem, ipsum, dolor }" parameter type annotation colon.
+
+(foo:{ a: string, b: number }) => {}
+// Message: There must be a space after "foo" parameter type annotation colon.
+
+({ a, b } :{ a: string, b: number }) => {}
+// Message: There must be a space after "{ a, b }" parameter type annotation colon.
+
+([ a, b ] :string[]) => {}
+// Message: There must be a space after "[ a, b ]" parameter type annotation colon.
+
+(i?:number) => {}
+// Message: There must be a space after "i" parameter type annotation colon.
+
+(i?: number) => {}
+// Message: There must be 1 space after "i" parameter type annotation colon.
+
+// Options: ["never"]
+(i?: number) => {}
+// Message: There must be no space after "i" parameter type annotation colon.
+
+// Options: ["always"]
+():Object => {}
+// Message: There must be a space after return type colon.
+
+// Options: ["never"]
+(): Object => {}
+// Message: There must be no space after return type colon.
+
+// Options: ["always"]
+(): Object => {}
+// Message: There must be 1 space after return type colon.
+
+// Options: ["always"]
+():(() => void) => {}
+// Message: There must be a space after return type colon.
+
+// Options: ["never"]
+(): (() => void) => {}
+// Message: There must be no space after return type colon.
+
+// Options: ["always"]
+(): (() => void) => {}
+// Message: There must be 1 space after return type colon.
+
+// Options: ["never"]
+export default function (foo: string) {}
+// Message: There must be no space after "foo" parameter type annotation colon.
+
+// Options: ["never"]
+function foo (foo: string) {}
+// Message: There must be no space after "foo" parameter type annotation colon.
+
+// Options: ["always"]
+(foo:string) => {}
+// Message: There must be a space after "foo" parameter type annotation colon.
+
+function foo (foo:string) {}
+// Message: There must be a space after "foo" parameter type annotation colon.
+
+async function foo({ lorem, ipsum, dolor }:SomeType) {}
+// Message: There must be a space after "{ lorem, ipsum, dolor }" parameter type annotation colon.
+
+function x(i?:number) {}
+// Message: There must be a space after "i" parameter type annotation colon.
+
+function x(i?: number) {}
+// Message: There must be 1 space after "i" parameter type annotation colon.
+
+// Options: ["never"]
+function x(i?: number) {}
+// Message: There must be no space after "i" parameter type annotation colon.
+
+function a():x {}
+// Message: There must be a space after return type colon.
+
+// Options: ["always"]
+function a(): x {}
+// Message: There must be 1 space after return type colon.
+
+// Options: ["never"]
+function a(): x {}
+// Message: There must be no space after return type colon.
+
+type X = (foo:number) => string
+// Message: There must be a space after "foo" parameter type annotation colon.
+
+// Options: ["never"]
+type X = (foo: number) => string
+// Message: There must be no space after "foo" parameter type annotation colon.
+
+type X = (foo: number) => string
+// Message: There must be 1 space after "foo" parameter type annotation colon.
+
+type X = (foo:?number) => string
+// Message: There must be a space after "foo" parameter type annotation colon.
+
+type X = (foo:(number)) => string
+// Message: There must be a space after "foo" parameter type annotation colon.
+
+type X = (foo:((number))) => string
+// Message: There must be a space after "foo" parameter type annotation colon.
+
+type X = (foo: ((number))) => string
+// Message: There must be 1 space after "foo" parameter type annotation colon.
+
+// Options: ["never"]
+type X = (foo: ((number))) => string
+// Message: There must be no space after "foo" parameter type annotation colon.
+
+type X = (foo:?(number)) => string
+// Message: There must be a space after "foo" parameter type annotation colon.
+
+type TArrayPredicate = (el: T, i?:number) => boolean
+// Message: There must be a space after "i" parameter type annotation colon.
+
+type TArrayPredicate = (el: T, i?: number) => boolean
+// Message: There must be 1 space after "i" parameter type annotation colon.
+
+// Options: ["never"]
+type TArrayPredicate = (el:T, i?: number) => boolean
+// Message: There must be no space after "i" parameter type annotation colon.
+
+class X { foo:string }
+// Message: There must be a space after "foo" class property type annotation colon.
+
+// Options: ["never"]
+class X { foo: string }
+// Message: There must be no space after "foo" class property type annotation colon.
+
+class X { foo:?string }
+// Message: There must be a space after "foo" class property type annotation colon.
+
+// Options: ["never"]
+class X { foo: ?string }
+// Message: There must be no space after "foo" class property type annotation colon.
+
+class X { static foo:number }
+// Message: There must be a space after "foo" class property type annotation colon.
+
+// Options: ["never"]
+class X { static foo: number }
+// Message: There must be no space after "foo" class property type annotation colon.
+
+class X { static foo :number }
+// Message: There must be a space after "foo" class property type annotation colon.
+
+// Options: ["never"]
+class X { static foo : number }
+// Message: There must be no space after "foo" class property type annotation colon.
+
+declare class X { static foo:number }
+// Message: There must be a space after "foo" type annotation colon.
+
+// Options: ["never"]
+declare class X { static foo: number }
+// Message: There must be no space after "foo" type annotation colon.
+
+declare class X { static foo :number }
+// Message: There must be a space after "foo" type annotation colon.
+
+// Options: ["never"]
+declare class X { static foo : number }
+// Message: There must be no space after "foo" type annotation colon.
+
+class X { +foo:string }
+// Message: There must be a space after "foo" class property type annotation colon.
+
+class X { +foo: string }
+// Message: There must be 1 space after "foo" class property type annotation colon.
+
+// Options: ["never"]
+class X { +foo: string }
+// Message: There must be no space after "foo" class property type annotation colon.
+
+class X { static +foo:string }
+// Message: There must be a space after "foo" class property type annotation colon.
+
+class X { static +foo: string }
+// Message: There must be 1 space after "foo" class property type annotation colon.
+
+// Options: ["never"]
+class X { static +foo: string }
+// Message: There must be no space after "foo" class property type annotation colon.
+
+type X = { foo:string }
+// Message: There must be a space after "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { foo:string }
+// Message: There must be a space after "foo" type annotation colon.
+
+// Options: ["never"]
+type X = { foo: string }
+// Message: There must be no space after "foo" type annotation colon.
+
+type X = { foo: string }
+// Message: There must be 1 space after "foo" type annotation colon.
+
+type X = { foo?:string }
+// Message: There must be a space after "foo" type annotation colon.
+
+// Options: ["never"]
+type X = { foo?: string }
+// Message: There must be no space after "foo" type annotation colon.
+
+type X = { foo?:?string }
+// Message: There must be a space after "foo" type annotation colon.
+
+type X = { foo?: ?string }
+// Message: There must be 1 space after "foo" type annotation colon.
+
+type Foo = { barType:(string | () => void) }
+// Message: There must be a space after "barType" type annotation colon.
+
+type Foo = { barType:(((string | () => void))) }
+// Message: There must be a space after "barType" type annotation colon.
+
+// Options: ["never"]
+type Foo = { barType: (string | () => void) }
+// Message: There must be no space after "barType" type annotation colon.
+
+type Foo = { barType: (string | () => void) }
+// Message: There must be 1 space after "barType" type annotation colon.
+
+type Foo = { barType: ((string | () => void)) }
+// Message: There must be 1 space after "barType" type annotation colon.
+
+type X = { get:() => A; }
+// Message: There must be a space after "get" type annotation colon.
+
+type X = { get:<X>() => A; }
+// Message: There must be a space after "get" type annotation colon.
+
+// Options: ["never"]
+type X = { get: () => A; }
+// Message: There must be no space after "get" type annotation colon.
+
+// Options: ["never"]
+type X = { get: <X>() => A; }
+// Message: There must be no space after "get" type annotation colon.
+
+type X = { get: () => A; }
+// Message: There must be 1 space after "get" type annotation colon.
+
+type X = { get: <X>() => A; }
+// Message: There must be 1 space after "get" type annotation colon.
+
+type X = { +foo:string }
+// Message: There must be a space after "foo" type annotation colon.
+
+type X = { +foo: string }
+// Message: There must be 1 space after "foo" type annotation colon.
+
+// Options: ["never"]
+type X = { +foo: string }
+// Message: There must be no space after "foo" type annotation colon.
+
+type X = { +foo?:string }
+// Message: There must be a space after "foo" type annotation colon.
+
+type X = { +foo?: string }
+// Message: There must be 1 space after "foo" type annotation colon.
+
+// Options: ["never"]
+type X = { +foo?: string }
+// Message: There must be no space after "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { [a:b]: c }
+// Message: There must be a space after type annotation colon.
+
+// Options: ["never"]
+type X = { [a: b]:c }
+// Message: There must be no space after type annotation colon.
+
+// Options: ["always"]
+type X = { [a: b]: c }
+// Message: There must be 1 space after type annotation colon.
+
+// Options: ["always"]
+type X = { +[a:b]: c }
+// Message: There must be a space after type annotation colon.
+
+// Options: ["never"]
+type X = { +[a: b]:c }
+// Message: There must be no space after type annotation colon.
+
+// Options: ["always"]
+type X = { +[a: b]: c }
+// Message: There must be 1 space after type annotation colon.
+
+// Options: ["always"]
+type X = { [a: b]:c }
+// Message: There must be a space after type annotation colon.
+
+// Options: ["never"]
+type X = { [a:b]: c }
+// Message: There must be no space after type annotation colon.
+
+// Options: ["always"]
+type X = { [a: b]: c }
+// Message: There must be 1 space after type annotation colon.
+
+// Options: ["always"]
+type X = { [a:b]:c }
+// Message: There must be a space after type annotation colon.
+// Message: There must be a space after type annotation colon.
+
+// Options: ["never"]
+type X = { [a: b]: c }
+// Message: There must be no space after type annotation colon.
+// Message: There must be no space after type annotation colon.
+
+// Options: ["always"]
+type X = { [a: b]: c }
+// Message: There must be 1 space after type annotation colon.
+// Message: There must be 1 space after type annotation colon.
+
+// Options: ["always"]
+type X = { [a:(b)]:(c) }
+// Message: There must be a space after type annotation colon.
+// Message: There must be a space after type annotation colon.
+
+// Options: ["never"]
+type X = { [a: (b)]: (c) }
+// Message: There must be no space after type annotation colon.
+// Message: There must be no space after type annotation colon.
+
+// Options: ["never"]
+const x = ({}: {})
+// Message: There must be no space after type cast colon.
+
+// Options: ["always"]
+const x = ({}:{})
+// Message: There must be a space after type cast colon.
+
+// Options: ["always"]
+const x = ({}: {})
+// Message: There must be 1 space after type cast colon.
+
+// Options: ["never"]
+((x): (string))
+// Message: There must be no space after type cast colon.
+
+// Options: ["always"]
+((x):(string))
+// Message: There must be a space after type cast colon.
+
+// Options: ["always"]
+((x): (string))
+// Message: There must be 1 space after type cast colon.
+```
+
+The following patterns are not considered problems:
+
+```js
+(foo) => {}
+
+(foo: string) => {}
+
+(foo: (string|number)) => {}
+
+// Options: ["never"]
+(foo:string) => {}
+
+// Options: ["always"]
+(foo: string) => {}
+
+// Options: ["never"]
+(foo:(() => void)) => {}
+
+// Options: ["always"]
+(foo: (() => void)) => {}
+
+({ lorem, ipsum, dolor }: SomeType) => {}
+
+(foo: { a: string, b: number }) => {}
+
+({ a, b }: ?{ a: string, b: number }) => {}
+
+([ a, b ]: string[]) => {}
+
+(i?: number) => {}
+
+// Options: ["never"]
+(i?:number) => {}
+
+// Options: ["never"]
+():Object => {}
+
+// Options: ["always"]
+(): Object => {}
+
+// Options: ["never"]
+():(number | string) => {}
+
+// Options: ["always"]
+(): (number | string) => {}
+
+// Options: ["never"]
+():number|string => {}
+
+// Options: ["always"]
+(): number|string => {}
+
+// Options: ["never"]
+():(() => void) => {}
+
+// Options: ["always"]
+(): (() => void) => {}
+
+// Options: ["never"]
+():( () => void ) => {}
+
+// Options: ["always"]
+(): ( () => void ) => {}
+
+(): { a: number, b: string } => {}
+
+// Options: ["never"]
+() :{ a:number, b:string } => {}
+
+function x(foo: string) {}
+
+class Foo { constructor(foo: string) {} }
+
+// Options: ["never"]
+function x(foo:string) {}
+
+// Options: ["never"]
+class Foo { constructor(foo:string) {} }
+
+async function foo({ lorem, ipsum, dolor }: SomeType) {}
+
+function x({ a, b }: { a: string, b: number }) {}
+
+function x(i?: number) {}
+
+// Options: ["never"]
+function x(i?:number) {}
+
+function a(): x {}
+
+// Options: ["never"]
+function a():x {}
+
+function a(): (number | string) {}
+
+// Options: ["never"]
+function a() :(number | string) {}
+
+type X = (foo: number) => string;
+
+type X = (foo : number) => string;
+
+type X = (foo: ?number) => string;
+
+type X = (foo? : ?number) => string;
+
+type X = (foo: ?{ x: number }) => string;
+
+// Options: ["never"]
+type X = (foo:number) => string;
+
+// Options: ["never"]
+type X = (foo:?{ x:number }) => string;
+
+type X = (foo: (number)) => string
+
+type X = (foo: ((number))) => string
+
+// Options: ["never"]
+type X = (foo:((number))) => string
+
+type X = ?(foo: ((number))) => string
+
+// Options: ["never"]
+type X = ?(foo:((number))) => string
+
+type TArrayPredicate = (el: T, i?: number) => boolean
+
+// Options: ["never"]
+type TArrayPredicate = (el:T, i?:number) => boolean
+
+class Foo { bar }
+
+class Foo { bar = 3 }
+
+class Foo { bar: string }
+
+class Foo { bar: ?string }
+
+// Options: ["never"]
+class Foo { bar:string }
+
+// Options: ["never"]
+class Foo { bar:?string }
+
+class X { static foo : number }
+
+// Options: ["never"]
+class X { static foo :number }
+
+declare class X { static foo : number }
+
+// Options: ["never"]
+declare class X { static foo :number }
+
+class X { +foo: string }
+
+class X { static +foo: string }
+
+// Options: ["never"]
+class X { +foo:string }
+
+// Options: ["never"]
+class X { static +foo:string }
+
+type X = { foo: string }
+
+// Options: ["never"]
+type X = { foo:string }
+
+type X = { foo?: string }
+
+type X = { foo?: ?string }
+
+// Options: ["never"]
+type X = { foo?:?string }
+
+type Foo = { barType: (string | () => void) }
+
+type Foo = { barType: ((string | () => void)) }
+
+// Options: ["never"]
+type Foo = { barType:(string | () => void) }
+
+// Options: ["never"]
+type Foo = { barType:((string | () => void)) }
+
+type X = { get(): A; }
+
+type X = { get<X>(): A; }
+
+// Options: ["never"]
+type X = { get(): A; }
+
+// Options: ["never"]
+type X = { get<X>(): A; }
+
+type X = { get: () => A; }
+
+type X = { get: <X>() => A; }
+
+// Options: ["never"]
+type X = { get:() => A; }
+
+// Options: ["never"]
+type X = { get:<X>() => A; }
+
+type X = { +foo: string }
+
+type X = { +foo?: string }
+
+// Options: ["never"]
+type X = { +foo:string }
+
+// Options: ["never"]
+type X = { +foo?:string }
+
+// Options: ["always"]
+type X = { [a: b]: c }
+
+// Options: ["never"]
+type X = { [a:b]:c }
+
+// Options: ["always"]
+type X = { +[a: b]: c }
+
+// Options: ["never"]
+type X = { +[a:b]:c }
+
+// Options: ["never"]
+const x = ({}:{})
+
+// Options: ["always"]
+const x = ({}: {})
+
+// Options: ["never"]
+((x):(string))
+
+// Options: ["always"]
+((x): (string))
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-space-before-generic-bracket"></a>
+### <code>space-before-generic-bracket</code>
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing before the opening `<` of generic type annotation parameters.
+
+This rule takes one argument. If it is `'never'` then a problem is raised when there is a space before the `<`. If it is `'always'` then a problem is raised when there is no space before the `<`.
+
+The default value is `'never'`.
+
+The following patterns are considered problems:
+
+```js
+type X = Promise <string>
+// Message: There must be no space before "Promise" generic type annotation bracket
+
+// Options: ["never"]
+type X = Promise <string>
+// Message: There must be no space before "Promise" generic type annotation bracket
+
+type X = Promise <string>
+// Message: There must be no space before "Promise" generic type annotation bracket
+
+// Options: ["always"]
+type X = Promise<string>
+// Message: There must be a space before "Promise" generic type annotation bracket
+
+// Options: ["always"]
+type X = Promise <string>
+// Message: There must be one space before "Promise" generic type annotation bracket
+```
+
+The following patterns are not considered problems:
+
+```js
+type X = Promise<string>
+
+// Options: ["always"]
+type X = Promise <string>
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-space-before-type-colon"></a>
+### <code>space-before-type-colon</code>
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing before the type annotation colon.
+
+This rule takes one argument. If it is `'always'` then a problem is raised when there is no space before the type annotation colon. If it is `'never'` then a problem is raised when there is a space before the type annotation colon. The default value is `'never'`.
+
+The following patterns are considered problems:
+
+```js
+// Options: ["never"]
+(foo : string) => {}
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+// Options: ["never"]
+(foo ? : string) => {}
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+(foo: string) => {}
+// Message: There must be a space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+(foo : string) => {}
+// Message: There must be 1 space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+(foo?: string) => {}
+// Message: There must be a space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+(foo ? : string) => {}
+// Message: There must be 1 space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+(foo ?: string) => {}
+// Message: There must be a space before "foo" parameter type annotation colon.
+
+({ lorem, ipsum, dolor } : SomeType) => {}
+// Message: There must be no space before "{ lorem, ipsum, dolor }" parameter type annotation colon.
+
+(foo : { a: string, b: number }) => {}
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+({ a, b } : { a: string, b: number }) => {}
+// Message: There must be no space before "{ a, b }" parameter type annotation colon.
+
+([ a, b ] : string[]) => {}
+// Message: There must be no space before "[ a, b ]" parameter type annotation colon.
+
+() : x => {}
+// Message: There must be no space before return type colon.
+
+// Options: ["always"]
+(): x => {}
+// Message: There must be a space before return type colon.
+
+// Options: ["always"]
+() : x => {}
+// Message: There must be 1 space before return type colon.
+
+function x(foo : string) {}
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+function x(foo: string) {}
+// Message: There must be a space before "foo" parameter type annotation colon.
+
+var x = function (foo : string) {}
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+var x = function (foo: string) {}
+// Message: There must be a space before "foo" parameter type annotation colon.
+
+class Foo { constructor(foo : string ) {} }
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+class Foo { constructor(foo: string ) {} }
+// Message: There must be a space before "foo" parameter type annotation colon.
+
+async function foo({ lorem, ipsum, dolor } : SomeType) {}
+// Message: There must be no space before "{ lorem, ipsum, dolor }" parameter type annotation colon.
+
+function a() : x {}
+// Message: There must be no space before return type colon.
+
+// Options: ["always"]
+function a(): x {}
+// Message: There must be a space before return type colon.
+
+// Options: ["always"]
+function a() : x {}
+// Message: There must be 1 space before return type colon.
+
+type X = (foo :string) => string;
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+type X = (foo:string) => string;
+// Message: There must be a space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+type X = (foo :string) => string;
+// Message: There must be 1 space before "foo" parameter type annotation colon.
+
+type X = (foo? :string) => string;
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+type X = (foo? :string) => string;
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+// Options: ["always"]
+type X = (foo?:string) => string;
+// Message: There must be a space before "foo" parameter type annotation colon.
+
+type X = (foo? :?string) => string;
+// Message: There must be no space before "foo" parameter type annotation colon.
+
+class X { foo :string }
+// Message: There must be no space before "foo" class property type annotation colon.
+
+// Options: ["always"]
+class X { foo: string }
+// Message: There must be a space before "foo" class property type annotation colon.
+
+class X { foo :?string }
+// Message: There must be no space before "foo" class property type annotation colon.
+
+// Options: ["always"]
+class X { foo: ?string }
+// Message: There must be a space before "foo" class property type annotation colon.
+
+class X { static foo : number }
+// Message: There must be no space before "foo" class property type annotation colon.
+
+class X { static foo :number }
+// Message: There must be no space before "foo" class property type annotation colon.
+
+// Options: ["always"]
+class X { static foo: number }
+// Message: There must be a space before "foo" class property type annotation colon.
+
+// Options: ["always"]
+class X { static foo:number }
+// Message: There must be a space before "foo" class property type annotation colon.
+
+declare class Foo { static bar :number; }
+// Message: There must be no space before "bar" type annotation colon.
+
+declare class Foo { static bar : number; }
+// Message: There must be no space before "bar" type annotation colon.
+
+// Options: ["always"]
+declare class Foo { static bar:number; }
+// Message: There must be a space before "bar" type annotation colon.
+
+// Options: ["always"]
+declare class Foo { static bar: number; }
+// Message: There must be a space before "bar" type annotation colon.
+
+// Options: ["always"]
+class X { +foo: string }
+// Message: There must be a space before "foo" class property type annotation colon.
+
+// Options: ["always"]
+class X { +foo : string }
+// Message: There must be 1 space before "foo" class property type annotation colon.
+
+// Options: ["never"]
+class X { +foo : string }
+// Message: There must be no space before "foo" class property type annotation colon.
+
+// Options: ["always"]
+class X { static +foo: string }
+// Message: There must be a space before "foo" class property type annotation colon.
+
+// Options: ["always"]
+class X { static +foo : string }
+// Message: There must be 1 space before "foo" class property type annotation colon.
+
+// Options: ["never"]
+class X { static +foo : string }
+// Message: There must be no space before "foo" class property type annotation colon.
+
+type X = { foo : string }
+// Message: There must be no space before "foo" type annotation colon.
+
+// Options: ["never"]
+type X = { foo : string }
+// Message: There must be no space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { foo: string }
+// Message: There must be a space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { foo : string }
+// Message: There must be 1 space before "foo" type annotation colon.
+
+type X = { foo? : string }
+// Message: There must be no space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { foo?: string }
+// Message: There must be a space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { foo? : string }
+// Message: There must be 1 space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { foo ?: string }
+// Message: There must be a space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { +foo: string }
+// Message: There must be a space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { +foo : string }
+// Message: There must be 1 space before "foo" type annotation colon.
+
+// Options: ["never"]
+type X = { +foo : string }
+// Message: There must be no space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { +foo?: string }
+// Message: There must be a space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { +foo? : string }
+// Message: There must be 1 space before "foo" type annotation colon.
+
+// Options: ["never"]
+type X = { +foo? : string }
+// Message: There must be no space before "foo" type annotation colon.
+
+// Options: ["always"]
+type X = { [a: b] : c }
+// Message: There must be a space before type annotation colon.
+
+// Options: ["never"]
+type X = { [a : b]: c }
+// Message: There must be no space before type annotation colon.
+
+// Options: ["always"]
+type X = { [a : b] : c }
+// Message: There must be 1 space before type annotation colon.
+
+// Options: ["always"]
+type X = { +[a:b] : c }
+// Message: There must be a space before type annotation colon.
+
+// Options: ["never"]
+type X = { +[a : b]: c }
+// Message: There must be no space before type annotation colon.
+
+// Options: ["always"]
+type X = { +[a : b] : c }
+// Message: There must be 1 space before type annotation colon.
+
+// Options: ["always"]
+type X = { [a : b]: c }
+// Message: There must be a space before type annotation colon.
+
+// Options: ["never"]
+type X = { [a: b] : c }
+// Message: There must be no space before type annotation colon.
+
+// Options: ["always"]
+type X = { [a : b] : c }
+// Message: There must be 1 space before type annotation colon.
+
+// Options: ["always"]
+type X = { [a:b]:c }
+// Message: There must be a space before type annotation colon.
+// Message: There must be a space before type annotation colon.
+
+// Options: ["never"]
+type X = { [a : b] : c }
+// Message: There must be no space before type annotation colon.
+// Message: There must be no space before type annotation colon.
+
+// Options: ["always"]
+type X = { [a : b] : c }
+// Message: There must be 1 space before type annotation colon.
+// Message: There must be 1 space before type annotation colon.
+
+// Options: ["always"]
+type X = { [a:(b)]:(c) }
+// Message: There must be a space before type annotation colon.
+// Message: There must be a space before type annotation colon.
+
+// Options: ["never"]
+type X = { [a : (b)] : (c) }
+// Message: There must be no space before type annotation colon.
+// Message: There must be no space before type annotation colon.
+
+// Options: ["never"]
+const x = ({} :{})
+// Message: There must be no space before type cast colon.
+
+// Options: ["always"]
+const x = ({}:{})
+// Message: There must be a space before type cast colon.
+
+// Options: ["always"]
+const x = ({} :{})
+// Message: There must be 1 space before type cast colon.
+
+// Options: ["never"]
+((x) : string)
+// Message: There must be no space before type cast colon.
+
+// Options: ["always"]
+((x): string)
+// Message: There must be a space before type cast colon.
+
+// Options: ["always"]
+((x) : string)
+// Message: There must be 1 space before type cast colon.
+```
+
+The following patterns are not considered problems:
+
+```js
+(foo) => {}
+
+(foo: string) => {}
+
+(foo?: string) => {}
+
+(foo ?: string) => {}
+
+// Options: ["never"]
+(foo: string) => {}
+
+// Options: ["always"]
+(foo : string) => {}
+
+// Options: ["always"]
+(foo? : string) => {}
+
+// Options: ["always"]
+(foo ? : string) => {}
+
+// Options: ["always"]
+(foo ? : string) => {}
+
+({ lorem, ipsum, dolor }: SomeType) => {}
+
+(foo: { a: string, b: number }) => {}
+
+({ a, b }: ?{ a: string, b: number }) => {}
+
+(): { a: number, b: string } => {}
+
+// Options: ["always"]
+() : { a : number, b : string } => {}
+
+([ a, b ]: string[]) => {}
+
+(): x => {}
+
+// Options: ["always"]
+() : x => {}
+
+(): (number | string) => {}
+
+// Options: ["always"]
+() : (number | string) => {}
+
+function x(foo: string) {}
+
+// Options: ["always"]
+function x(foo : string) {}
+
+var x = function (foo: string) {}
+
+// Options: ["always"]
+var x = function (foo : string) {}
+
+class X { foo({ bar }: Props = this.props) {} }
+
+class Foo { constructor(foo: string ) {} }
+
+// Options: ["always"]
+class Foo { constructor(foo : string ) {} }
+
+async function foo({ lorem, ipsum, dolor }: SomeType) {}
+
+function x({ a, b }: { a: string, b: number }) {}
+
+function a(): x {}
+
+// Options: ["always"]
+function a() : x {}
+
+function a(): (number | string) {}
+
+// Options: ["always"]
+function a() : (number | string) {}
+
+type X = (foo:string) => number;
+
+type X = (foo: string) => number;
+
+type X = (foo: ?string) => number;
+
+type X = (foo?: string) => number;
+
+type X = (foo?: ?string) => number;
+
+type X = (foo ?: string) => number;
+
+// Options: ["always"]
+type X = (foo? : string) => number
+
+// Options: ["always"]
+type X = (foo? : ?string) => number
+
+class Foo { bar }
+
+class Foo { bar = 3 }
+
+class Foo { bar: string }
+
+class Foo { bar: ?string }
+
+class Foo { bar:?string }
+
+// Options: ["always"]
+class Foo { bar : string }
+
+class X { static foo:number }
+
+class X { static foo: number }
+
+// Options: ["always"]
+class X { static foo :number }
+
+// Options: ["always"]
+class X { static foo : number }
+
+declare class Foo { static bar:number; }
+
+// Options: ["always"]
+declare class Foo { static bar :number; }
+
+declare class Foo { static bar: number; }
+
+// Options: ["always"]
+declare class Foo { static bar : number; }
+
+class X { +foo: string }
+
+class X { static +foo: string }
+
+// Options: ["always"]
+class X { +foo : string }
+
+// Options: ["always"]
+class X { static +foo : string }
+
+type X = { foo: string }
+
+// Options: ["always"]
+type X = { foo : string }
+
+type X = { foo?: string }
+
+type X = { foo ?: string }
+
+// Options: ["always"]
+type X = { foo? : string }
+
+type X = { +foo: string }
+
+type X = { +foo?: string }
+
+// Options: ["always"]
+type X = { +foo : string }
+
+// Options: ["always"]
+type X = { +foo? : string }
+
+// Options: ["always"]
+type X = { [a : b] : c }
+
+// Options: ["never"]
+type X = { [a:b]:c }
+
+// Options: ["always"]
+type X = { +[a : b] : c }
+
+// Options: ["never"]
+type X = { +[a:b]:c }
+
+// Options: ["always"]
+type X = { [a : (b)] : (c) }
+
+// Options: ["never"]
+type X = { [a:(b)]:(c) }
+
+// Options: ["never"]
+const x = ({}:{})
+
+// Options: ["always"]
+const x = ({} :{})
+
+// Options: ["never"]
+((x): string)
+
+// Options: ["always"]
+((x) : string)
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-type-id-match"></a>
+### <code>type-id-match</code>
+
+Enforces a consistent naming pattern for type aliases.
+
+<a name="eslint-plugin-flowtype-rules-type-id-match-options"></a>
+#### Options
+
+This rule needs a text RegExp to operate with Its signature is as follows:
+
+```js
+{
+ "rules": {
+ "flowtype/type-id-match": [
+ 2,
+ "^([A-Z][a-z0-9]*)+Type$"
+ ]
+ }
+}
+```
+
+`'^([A-Z][a-z0-9]*)+Type$'` is the default pattern.
+
+The following patterns are considered problems:
+
+```js
+type foo = {};
+// Message: Type identifier 'foo' does not match pattern '/^([A-Z][a-z0-9]*)+Type$/'.
+
+// Options: ["^foo$"]
+type FooType = {};
+// Message: Type identifier 'FooType' does not match pattern '/^foo$/'.
+```
+
+The following patterns are not considered problems:
+
+```js
+type FooType = {};
+
+// Options: ["^foo$"]
+type foo = {};
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-union-intersection-spacing"></a>
+### <code>union-intersection-spacing</code>
+
+_The `--fix` option on the command line automatically fixes problems reported by this rule._
+
+Enforces consistent spacing around union and intersection type separators (`|` and `&`).
+
+This rule takes one argument. If it is `'always'` then a problem is raised when there is no space around the separator. If it is `'never'` then a problem is raised when there is a space around the separator.
+
+The default value is `'always'`.
+
+The following patterns are considered problems:
+
+```js
+type X = string| number;
+// Message: There must be a space before union type annotation separator
+
+// Options: ["always"]
+type X = string| number;
+// Message: There must be a space before union type annotation separator
+
+type X = string |number;
+// Message: There must be a space after union type annotation separator
+
+type X = string|number;
+// Message: There must be a space before union type annotation separator
+// Message: There must be a space after union type annotation separator
+
+type X = {x: string}|{y: number};
+// Message: There must be a space before union type annotation separator
+// Message: There must be a space after union type annotation separator
+
+type X = string | number |boolean;
+// Message: There must be a space after union type annotation separator
+
+type X = string|number|boolean;
+// Message: There must be a space before union type annotation separator
+// Message: There must be a space after union type annotation separator
+// Message: There must be a space before union type annotation separator
+// Message: There must be a space after union type annotation separator
+
+type X = (string)| number;
+// Message: There must be a space before union type annotation separator
+
+type X = ((string))|(number | foo);
+// Message: There must be a space before union type annotation separator
+// Message: There must be a space after union type annotation separator
+
+// Options: ["never"]
+type X = string |number;
+// Message: There must be no space before union type annotation separator
+
+// Options: ["never"]
+type X = string| number;
+// Message: There must be no space after union type annotation separator
+
+type X = string& number;
+// Message: There must be a space before intersection type annotation separator
+
+// Options: ["always"]
+type X = string& number;
+// Message: There must be a space before intersection type annotation separator
+
+type X = string &number;
+// Message: There must be a space after intersection type annotation separator
+
+type X = {x: string}&{y: number};
+// Message: There must be a space before intersection type annotation separator
+// Message: There must be a space after intersection type annotation separator
+
+type X = string&number;
+// Message: There must be a space before intersection type annotation separator
+// Message: There must be a space after intersection type annotation separator
+
+type X = string & number &boolean;
+// Message: There must be a space after intersection type annotation separator
+
+type X = string&number&boolean;
+// Message: There must be a space before intersection type annotation separator
+// Message: There must be a space after intersection type annotation separator
+// Message: There must be a space before intersection type annotation separator
+// Message: There must be a space after intersection type annotation separator
+
+type X = (string)& number;
+// Message: There must be a space before intersection type annotation separator
+
+type X = ((string))&(number & foo);
+// Message: There must be a space before intersection type annotation separator
+// Message: There must be a space after intersection type annotation separator
+
+// Options: ["never"]
+type X = string &number;
+// Message: There must be no space before intersection type annotation separator
+
+// Options: ["never"]
+type X = string& number;
+// Message: There must be no space after intersection type annotation separator
+```
+
+The following patterns are not considered problems:
+
+```js
+type X = string | number;
+
+type X = string | number | boolean;
+
+type X = (string) | number;
+
+type X = ((string)) | (number | foo);
+
+// Options: ["never"]
+type X = string|number
+
+type X =
+| string
+| number
+
+function x() {
+type X =
+| string
+| number
+}
+
+type X = string & number;
+
+type X = string & number & boolean;
+
+type X = (string) & number;
+
+type X = ((string)) & (number & foo);
+
+// Options: ["never"]
+type X = string&number
+
+type X =
+& string
+& number
+
+function x() {
+type X =
+& string
+& number
+}
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-use-flow-type"></a>
+### <code>use-flow-type</code>
+
+Marks Flow [type alias](https://flowtype.org/docs/type-aliases.html) declarations as used.
+
+Used to suppress [`no-unused-vars`](http://eslint.org/docs/rules/no-unused-vars) errors that are triggered by type aliases.
+
+The following patterns are not considered problems:
+
+```js
+declare class A {}
+// Additional rules: {"no-unused-vars":1}
+
+declare function A(): Y
+// Additional rules: {"no-unused-vars":1}
+
+declare module A {}
+// Additional rules: {"no-unused-vars":1}
+
+declare module A { declare var a: Y }
+// Additional rules: {"no-unused-vars":1}
+
+declare var A: Y
+// Additional rules: {"no-unused-vars":1}
+
+import type A from "a"; (function<T: A>(): T {})
+// Additional rules: {"no-unused-vars":1}
+
+(function<T: A>(): T {}); import type A from "a"
+// Additional rules: {"no-unused-vars":1}
+
+import type {A} from "a"; (function<T: A>(): T {})
+// Additional rules: {"no-unused-vars":1}
+
+(function<T: A>(): T {}); import type {A} from "a"
+// Additional rules: {"no-unused-vars":1}
+
+(function<T: A>(): T {}); import type {a as A} from "a"
+// Additional rules: {"no-unused-vars":1}
+
+type A = {}; function x<Y: A>(i: Y) { i }; x()
+// Additional rules: {"no-unused-vars":1}
+
+function x<Y: A>(i: Y) { i }; type A = {}; x()
+// Additional rules: {"no-unused-vars":1}
+
+type A = {}; function x<Y: A.B.C>(i: Y) { i }; x()
+// Additional rules: {"no-unused-vars":1}
+
+function x<Y: A.B.C>(i: Y) { i }; type A = {}; x()
+// Additional rules: {"no-unused-vars":1}
+```
+
+
+
+<a name="eslint-plugin-flowtype-rules-valid-syntax"></a>
+### <code>valid-syntax</code>
+
+**Deprecated** Babylon (the Babel parser) v6.10.0 fixes parsing of the invalid syntax this plugin warned against.
+
+Checks for simple Flow syntax errors.
+
diff --git a/bin/readmeAssertions.js b/bin/readmeAssertions.js
new file mode 100644
index 0000000..4b96260
--- /dev/null
+++ b/bin/readmeAssertions.js
@@ -0,0 +1,84 @@
+/**
+ * This script is used to inline assertions into the README.md documents.
+ */
+import _ from 'lodash';
+import glob from 'glob';
+import path from 'path';
+import fs from 'fs';
+
+const formatCodeSnippet = (setup) => {
+ const paragraphs = [];
+
+ if (setup.options) {
+ paragraphs.push('// Options: ' + JSON.stringify(setup.options));
+ }
+
+ paragraphs.push(setup.code);
+
+ if (setup.errors) {
+ setup.errors.forEach((message) => {
+ paragraphs.push('// Message: ' + message.message);
+ });
+ }
+
+ if (setup.rules) {
+ paragraphs.push('// Additional rules: ' + JSON.stringify(setup.rules));
+ }
+
+ return paragraphs.join('\n');
+};
+
+const getAssertions = () => {
+ const assertionFiles = glob.sync(path.resolve(__dirname, './../tests/rules/assertions/*.js'));
+
+ const assertionNames = _.map(assertionFiles, (filePath) => {
+ return path.basename(filePath, '.js');
+ });
+
+ const assertionCodes = _.map(assertionFiles, (filePath) => {
+ const codes = require(filePath);
+
+ return {
+ valid: _.map(codes.valid, formatCodeSnippet),
+ invalid: _.map(codes.invalid, formatCodeSnippet)
+ };
+ });
+
+ return _.zipObject(assertionNames, assertionCodes);
+};
+
+const updateDocuments = (assertions) => {
+ const readmeDocumentPath = path.join(__dirname, './../README.md');
+
+ let documentBody = fs.readFileSync(readmeDocumentPath, 'utf8');
+
+ documentBody = documentBody.replace(/<!-- assertions ([a-z]+?) -->/ig, (assertionsBlock) => {
+ let exampleBody;
+
+ const ruleName = assertionsBlock.match(/assertions ([a-z]+)/i)[1];
+
+ const ruleAssertions = assertions[ruleName];
+
+ if (!ruleAssertions) {
+ throw new Error('No assertions available for rule "' + ruleName + '".');
+
+ return assertionsBlock;
+ }
+
+ exampleBody = '';
+
+ if (ruleAssertions.invalid.length) {
+ exampleBody += 'The following patterns are considered problems:\n\n```js\n' + ruleAssertions.invalid.join('\n\n') + '\n```\n\n';
+ }
+
+ if (ruleAssertions.valid.length) {
+ exampleBody += 'The following patterns are not considered problems:\n\n```js\n' + ruleAssertions.valid.join('\n\n') + '\n```\n\n';
+ }
+
+ return exampleBody;
+ });
+
+ fs.writeFileSync(readmeDocumentPath, documentBody);
+};
+
+updateDocuments(getAssertions());
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..3447415
--- /dev/null
+++ b/package.json
@@ -0,0 +1,57 @@
+{
+ "name": "eslint-plugin-flowtype",
+ "description": "Flowtype linting rules for ESLint.",
+ "version": "2.25.0",
+ "main": "./dist/index.js",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/gajus/eslint-plugin-flowtype"
+ },
+ "keywords": [
+ "eslint",
+ "plugin",
+ "flowtype"
+ ],
+ "author": {
+ "name": "Gajus Kuizinas",
+ "email": "gajus at gajus.com",
+ "url": "http://gajus.com"
+ },
+ "license": "BSD-3-Clause",
+ "peerDependencies": {
+ "eslint": ">=2.0.0"
+ },
+ "dependencies": {
+ "lodash": "^4.15.0"
+ },
+ "scripts": {
+ "lint": "eslint ./src ./tests",
+ "test": "mocha --compilers js:babel-register ./tests/rules/index.js",
+ "build": "babel ./src --out-dir ./dist --copy-files",
+ "documentation-add-assertions": "babel-node ./bin/readmeAssertions",
+ "documentation": "gitdown ./.README/README.md --output-file ./README.md; npm run documentation-add-assertions",
+ "create-index": "create-index ./src --update-index",
+ "precommit": "npm run lint && npm run test && npm run format-json",
+ "commitmsg": "conventional-changelog-lint -e",
+ "format-json": "jsonlint --sort-keys --in-place --indent ' ' ./src/configs/recommended.json && echo '' >> ./src/configs/recommended.json"
+ },
+ "devDependencies": {
+ "babel-cli": "^6.14.0",
+ "babel-eslint": "^6.1.2",
+ "babel-plugin-add-module-exports": "^0.2.1",
+ "babel-preset-es2015": "^6.14.0",
+ "babel-preset-stage-0": "^6.5.0",
+ "babel-register": "^6.14.0",
+ "chai": "^3.5.0",
+ "conventional-changelog-lint": "^1.0.1",
+ "create-index": "^0.1.3",
+ "eslint": "^3.4.0",
+ "eslint-config-canonical": "1.8.1",
+ "gitdown": "^2.5.0",
+ "husky": "^0.11.7",
+ "jsonlint": "^1.6.2",
+ "mocha": "^3.0.2",
+ "standard-version": "^2.4.0",
+ "travis-after-all": "^1.4.4"
+ }
+}
diff --git a/src/configs/recommended.json b/src/configs/recommended.json
new file mode 100644
index 0000000..dc14900
--- /dev/null
+++ b/src/configs/recommended.json
@@ -0,0 +1,44 @@
+{
+ "parser": "babel-eslint",
+ "rules": {
+ "flowtype/boolean-style": [
+ 2,
+ "boolean"
+ ],
+ "flowtype/define-flow-type": 1,
+ "flowtype/delimiter-dangle": 0,
+ "flowtype/generic-spacing": [
+ 2,
+ "never"
+ ],
+ "flowtype/no-weak-types": 0,
+ "flowtype/require-parameter-type": 0,
+ "flowtype/require-return-type": 0,
+ "flowtype/require-valid-file-annotation": 0,
+ "flowtype/semi": 0,
+ "flowtype/space-after-type-colon": [
+ 2,
+ "always"
+ ],
+ "flowtype/space-before-generic-bracket": [
+ 2,
+ "never"
+ ],
+ "flowtype/space-before-type-colon": [
+ 2,
+ "never"
+ ],
+ "flowtype/type-id-match": 0,
+ "flowtype/union-intersection-spacing": [
+ 2,
+ "always"
+ ],
+ "flowtype/use-flow-type": 1,
+ "flowtype/valid-syntax": 1
+ },
+ "settings": {
+ "flowtype": {
+ "onlyFilesWithFlowAnnotation": false
+ }
+ }
+}
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..0bae069
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,67 @@
+import defineFlowType from './rules/defineFlowType';
+import genericSpacing from './rules/genericSpacing';
+import noWeakTypes from './rules/noWeakTypes';
+import requireParameterType from './rules/requireParameterType';
+import requireReturnType from './rules/requireReturnType';
+import requireValidFileAnnotation from './rules/requireValidFileAnnotation';
+import semi from './rules/semi';
+import spaceAfterTypeColon from './rules/spaceAfterTypeColon';
+import spaceBeforeGenericBracket from './rules/spaceBeforeGenericBracket';
+import spaceBeforeTypeColon from './rules/spaceBeforeTypeColon';
+import unionIntersectionSpacing from './rules/unionIntersectionSpacing';
+import typeIdMatch from './rules/typeIdMatch';
+import useFlowType from './rules/useFlowType';
+import validSyntax from './rules/validSyntax';
+import booleanStyle from './rules/booleanStyle';
+import delimiterDangle from './rules/delimiterDangle';
+import noDupeKeys from './rules/noDupeKeys';
+import sortKeys from './rules/sortKeys';
+import objectTypeDelimiter from './rules/objectTypeDelimiter';
+import recommended from './configs/recommended.json';
+
+export default {
+ configs: {
+ recommended
+ },
+ rules: {
+ 'boolean-style': booleanStyle,
+ 'define-flow-type': defineFlowType,
+ 'delimiter-dangle': delimiterDangle,
+ 'generic-spacing': genericSpacing,
+ 'no-dupe-keys': noDupeKeys,
+ 'no-weak-types': noWeakTypes,
+ 'object-type-delimiter': objectTypeDelimiter,
+ 'require-parameter-type': requireParameterType,
+ 'require-return-type': requireReturnType,
+ 'require-valid-file-annotation': requireValidFileAnnotation,
+ semi,
+ 'sort-keys': sortKeys,
+ 'space-after-type-colon': spaceAfterTypeColon,
+ 'space-before-generic-bracket': spaceBeforeGenericBracket,
+ 'space-before-type-colon': spaceBeforeTypeColon,
+ 'type-id-match': typeIdMatch,
+ 'union-intersection-spacing': unionIntersectionSpacing,
+ 'use-flow-type': useFlowType,
+ 'valid-syntax': validSyntax
+ },
+ rulesConfig: {
+ 'boolean-style': 0,
+ 'define-flow-type': 0,
+ 'delimiter-dangle': 0,
+ 'generic-spacing': 0,
+ 'no-dupe-keys': 0,
+ 'no-weak-types': 0,
+ 'object-type-delimiter': 0,
+ 'require-parameter-type': 0,
+ 'require-return-type': 0,
+ semi: 0,
+ 'sort-keys': 0,
+ 'space-after-type-colon': 0,
+ 'space-before-generic-bracket': 0,
+ 'space-before-type-colon': 0,
+ 'type-id-match': 0,
+ 'union-intersection-spacing': 0,
+ 'use-flow-type': 0,
+ 'valid-syntax': 0
+ }
+};
diff --git a/src/rules/booleanStyle.js b/src/rules/booleanStyle.js
new file mode 100644
index 0000000..9ddad7b
--- /dev/null
+++ b/src/rules/booleanStyle.js
@@ -0,0 +1,29 @@
+export default (context) => {
+ const longForm = (context.options[0] || 'boolean') === 'boolean';
+
+ return {
+ BooleanTypeAnnotation (node) {
+ const diff = node.end - node.start;
+
+ if (longForm && diff === 4) {
+ context.report({
+ fix (fixer) {
+ return fixer.replaceText(node, 'boolean');
+ },
+ message: 'Use "boolean", not "bool"',
+ node
+ });
+ }
+
+ if (!longForm && diff !== 4) {
+ context.report({
+ fix (fixer) {
+ return fixer.replaceText(node, 'bool');
+ },
+ message: 'Use "bool", not "boolean"',
+ node
+ });
+ }
+ }
+ };
+};
diff --git a/src/rules/defineFlowType.js b/src/rules/defineFlowType.js
new file mode 100644
index 0000000..27e76a5
--- /dev/null
+++ b/src/rules/defineFlowType.js
@@ -0,0 +1,64 @@
+export const schema = [];
+
+export default (context) => {
+ let globalScope;
+
+ // do nearly the same thing that eslint does for config globals
+ // https://github.com/eslint/eslint/blob/v2.0.0/lib/eslint.js#L118-L194
+ const makeDefined = (ident) => {
+ let ii;
+
+ // start from the right since we're going to remove items from the array
+ for (ii = globalScope.through.length - 1; ii >= 0; ii--) {
+ const ref = globalScope.through[ii];
+
+ if (ref.identifier.name === ident.name) {
+ // use "__defineGeneric" since we don't have a reference to "escope.Variable"
+ globalScope.__defineGeneric( // eslint-disable-line no-underscore-dangle
+ ident.name,
+ globalScope.set,
+ globalScope.variables
+ );
+ const variable = globalScope.set.get(ident.name);
+
+ variable.writeable = false;
+ // "through" contains all references whose definition cannot be found
+ // so we need to update references and remove the ones that were added
+ globalScope.through.splice(ii, 1);
+ ref.resolved = variable;
+ variable.references.push(ref);
+ }
+ }
+ };
+
+ return {
+ ClassImplements (node) {
+ makeDefined(node.id);
+ },
+ GenericTypeAnnotation (node) {
+ if (node.id.type === 'Identifier') {
+ makeDefined(node.id);
+ } else if (node.id.type === 'QualifiedTypeIdentifier') {
+ let qid;
+
+ qid = node.id;
+ do {
+ qid = qid.qualification;
+ } while (qid.qualification);
+
+ makeDefined(qid);
+ }
+ },
+ InterfaceDeclaration (node) {
+ makeDefined(node.id);
+ },
+ Program () {
+ globalScope = context.getScope();
+ },
+ TypeParameterDeclaration (node) {
+ node.params.forEach((param) => {
+ makeDefined(param);
+ });
+ }
+ };
+};
diff --git a/src/rules/delimiterDangle.js b/src/rules/delimiterDangle.js
new file mode 100644
index 0000000..a71cd7b
--- /dev/null
+++ b/src/rules/delimiterDangle.js
@@ -0,0 +1,105 @@
+import _ from 'lodash';
+
+export default (context) => {
+ const option = context.options[0] || 'never';
+ const sourceCode = context.getSourceCode();
+
+ const reporter = (node, message, fix) => {
+ return () => {
+ context.report({
+ fix,
+ message,
+ node
+ });
+ };
+ };
+
+ const makeReporters = (node, tokenToFix) => {
+ return {
+ dangle: reporter(node, 'Unexpected trailing delimiter', (fixer) => {
+ return fixer.replaceText(tokenToFix, '');
+ }),
+ noDangle: reporter(node, 'Missing trailing delimiter', (fixer) => {
+ return fixer.insertTextAfter(tokenToFix, ',');
+ })
+ };
+ };
+
+ const evaluate = (node, lastChildNode) => {
+ if (!lastChildNode) {
+ return;
+ }
+
+ const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2);
+
+ const isDangling = [';', ','].indexOf(penultimateToken.value) > -1;
+ const isMultiLine = penultimateToken.loc.start.line !== lastToken.loc.start.line;
+
+ const report = makeReporters(lastChildNode, penultimateToken);
+
+ if (option === 'always' && !isDangling) {
+ report.noDangle();
+
+ return;
+ }
+
+ if (option === 'never' && isDangling) {
+ report.dangle();
+
+ return;
+ }
+
+ if (option === 'always-multiline' && !isDangling && isMultiLine) {
+ report.noDangle();
+
+ return;
+ }
+
+ if (option === 'always-multiline' && isDangling && !isMultiLine) {
+ report.dangle();
+
+ return;
+ }
+
+ if (option === 'only-multiline' && isDangling && !isMultiLine) {
+ report.dangle();
+
+ return;
+ }
+ };
+
+ // required for reporting the correct position
+ const getLast = (property, indexer) => {
+ if (!property) {
+ return indexer;
+ }
+
+ if (!indexer) {
+ return property;
+ }
+
+ if (property.loc.end.line > indexer.loc.end.line) {
+ return property;
+ }
+
+ if (indexer.loc.end.line > property.loc.end.line) {
+ return indexer;
+ }
+
+ if (property.loc.end.column > indexer.loc.end.column) {
+ return property;
+ }
+
+ return indexer;
+ };
+
+ return {
+ ObjectTypeAnnotation (node) {
+ evaluate(node, getLast(_.last(node.properties), _.last(node.indexers)));
+ },
+
+ TupleTypeAnnotation (node) {
+ evaluate(node, _.last(node.types));
+ }
+ };
+};
diff --git a/src/rules/genericSpacing.js b/src/rules/genericSpacing.js
new file mode 100644
index 0000000..e438e4f
--- /dev/null
+++ b/src/rules/genericSpacing.js
@@ -0,0 +1,78 @@
+import {spacingFixers} from './../utilities';
+
+export default (context) => {
+ const sourceCode = context.getSourceCode();
+
+ const never = (context.options[0] || 'never') === 'never';
+
+ return {
+ GenericTypeAnnotation (node) {
+ const types = node.typeParameters;
+
+ // Promise<foo>
+ // ^^^^^^^^^^^^ GenericTypeAnnotation (with typeParameters)
+ // ^^^ GenericTypeAnnotation (without typeParameters)
+ if (!types) {
+ return;
+ }
+
+ const [opener, firstInnerToken] = sourceCode.getFirstTokens(types, 2);
+ const [lastInnerToken, closer] = sourceCode.getLastTokens(types, 2);
+
+ const spacesBefore = firstInnerToken.start - opener.end;
+ const spacesAfter = closer.start - lastInnerToken.end;
+
+ if (never) {
+ if (spacesBefore) {
+ context.report({
+ data: {name: node.id.name},
+ fix: spacingFixers.stripSpacesAfter(opener, spacesBefore),
+ message: 'There must be no space at start of "{{name}}" generic type annotation',
+ node: types
+ });
+ }
+
+ if (spacesAfter) {
+ context.report({
+ data: {name: node.id.name},
+ fix: spacingFixers.stripSpacesAfter(lastInnerToken, spacesAfter),
+ message: 'There must be no space at end of "{{name}}" generic type annotation',
+ node: types
+ });
+ }
+ } else {
+ if (spacesBefore > 1) {
+ context.report({
+ data: {name: node.id.name},
+ fix: spacingFixers.stripSpacesAfter(opener, spacesBefore - 1),
+ message: 'There must be one space at start of "{{name}}" generic type annotation',
+ node: types
+ });
+ } else if (spacesBefore === 0) {
+ context.report({
+ data: {name: node.id.name},
+ fix: spacingFixers.addSpaceAfter(opener),
+ message: 'There must be a space at start of "{{name}}" generic type annotation',
+ node: types
+ });
+ }
+
+ if (spacesAfter > 1) {
+ context.report({
+ data: {name: node.id.name},
+ fix: spacingFixers.stripSpacesAfter(lastInnerToken, spacesAfter - 1),
+ message: 'There must be one space at end of "{{name}}" generic type annotation',
+ node: types
+ });
+ } else if (spacesAfter === 0) {
+ context.report({
+ data: {name: node.id.name},
+ fix: spacingFixers.addSpaceAfter(lastInnerToken),
+ message: 'There must be a space at end of "{{name}}" generic type annotation',
+ node: types
+ });
+ }
+ }
+ }
+ };
+};
diff --git a/src/rules/noDupeKeys.js b/src/rules/noDupeKeys.js
new file mode 100644
index 0000000..d419b2f
--- /dev/null
+++ b/src/rules/noDupeKeys.js
@@ -0,0 +1,32 @@
+import _ from 'lodash/';
+import {
+ getParameterName
+} from './../utilities';
+
+export default (context) => {
+ const report = (node) => {
+ context.report({
+ loc: node.loc,
+ message: 'Duplicate property.',
+ node
+ });
+ };
+
+ const checkForDuplicates = (node) => {
+ const haystack = [];
+
+ _.forEach(node.properties, (identifierNode) => {
+ const needle = getParameterName(identifierNode, context);
+
+ if (_.includes(haystack, needle)) {
+ report(identifierNode);
+ } else {
+ haystack.push(needle);
+ }
+ });
+ };
+
+ return {
+ ObjectTypeAnnotation: checkForDuplicates
+ };
+};
diff --git a/src/rules/noWeakTypes.js b/src/rules/noWeakTypes.js
new file mode 100644
index 0000000..bc99608
--- /dev/null
+++ b/src/rules/noWeakTypes.js
@@ -0,0 +1,42 @@
+import _ from 'lodash';
+
+const reportWeakType = (context, weakType) => {
+ return (node) => {
+ context.report({
+ data: {weakType},
+ message: 'Unexpected use of weak type "{{weakType}}"',
+ node
+ });
+ };
+};
+
+const genericTypeEvaluator = (context, {checkFunction, checkObject}) => {
+ return (node) => {
+ const name = _.get(node, 'id.name');
+
+ if (checkFunction && name === 'Function' || checkObject && name === 'Object') {
+ reportWeakType(context, name)(node);
+ }
+ };
+};
+
+export default (context) => {
+ const checkAny = _.get(context, 'options[0].any', true) === true;
+ const checkFunction = _.get(context, 'options[0].Function', true) === true;
+ const checkObject = _.get(context, 'options[0].Object', true) === true;
+
+ const checks = {};
+
+ if (checkAny) {
+ checks.AnyTypeAnnotation = reportWeakType(context, 'any');
+ }
+
+ if (checkFunction || checkObject) {
+ checks.GenericTypeAnnotation = genericTypeEvaluator(context, {
+ checkFunction,
+ checkObject
+ });
+ }
+
+ return checks;
+};
diff --git a/src/rules/objectTypeDelimiter.js b/src/rules/objectTypeDelimiter.js
new file mode 100644
index 0000000..d6265f0
--- /dev/null
+++ b/src/rules/objectTypeDelimiter.js
@@ -0,0 +1,59 @@
+ // ported from babel/flow-object-type; original author: Nat Mote
+ // https://github.com/babel/eslint-plugin-babel/blob/c0a49d25a97feb12c1d07073a0b37317359a5fe5/rules/flow-object-type.js
+
+const SEMICOLON = {
+ char: ';',
+ name: 'semicolon'
+};
+
+const COMMA = {
+ char: ',',
+ name: 'comma'
+};
+
+const create = (context) => {
+ let GOOD;
+ let BAD;
+
+ if (!context.options[0] || context.options[0] === COMMA.name) {
+ GOOD = COMMA;
+ BAD = SEMICOLON;
+ } else {
+ GOOD = SEMICOLON;
+ BAD = COMMA;
+ }
+
+ const requireProperPunctuation = (node) => {
+ const tokens = context.getSourceCode().getTokens(node);
+ const lastToken = tokens[tokens.length - 1];
+
+ if (lastToken.type === 'Punctuator') {
+ if (lastToken.value === BAD.char) {
+ context.report({
+ fix (fixer) {
+ return fixer.replaceText(lastToken, GOOD.char);
+ },
+ message: 'Prefer ' + GOOD.name + 's to ' + BAD.name + 's in object and class types',
+ node: lastToken
+ });
+ }
+ }
+ };
+
+ return {
+ ObjectTypeCallProperty: requireProperPunctuation,
+ ObjectTypeIndexer: requireProperPunctuation,
+ ObjectTypeProperty: requireProperPunctuation
+ };
+};
+
+const schema = [
+ {
+ enum: ['semicolon', 'comma']
+ }
+];
+
+export default {
+ create,
+ schema
+};
diff --git a/src/rules/requireParameterType.js b/src/rules/requireParameterType.js
new file mode 100644
index 0000000..5a7e2ce
--- /dev/null
+++ b/src/rules/requireParameterType.js
@@ -0,0 +1,47 @@
+import _ from 'lodash';
+import {
+ getParameterName,
+ isFlowFile,
+ iterateFunctionNodes,
+ quoteName
+} from './../utilities';
+
+export default iterateFunctionNodes((context) => {
+ const checkThisFile = !_.get(context, 'settings.flowtype.onlyFilesWithFlowAnnotation') || isFlowFile(context);
+
+ if (!checkThisFile) {
+ return () => {};
+ }
+
+ const skipArrows = _.get(context, 'options[0].excludeArrowFunctions');
+ const excludeParameterMatch = new RegExp(_.get(context, 'options[0].excludeParameterMatch', 'a^'));
+
+ return (functionNode) => {
+ _.forEach(functionNode.params, (identifierNode) => {
+ const parameterName = getParameterName(identifierNode, context);
+
+ if (excludeParameterMatch.test(parameterName)) {
+ return;
+ }
+
+ const typeAnnotation = _.get(identifierNode, 'typeAnnotation') || _.get(identifierNode, 'left.typeAnnotation');
+
+ const isArrow = functionNode.type === 'ArrowFunctionExpression';
+ const isArrowFunctionExpression = functionNode.expression;
+
+ if (skipArrows === 'expressionsOnly' && isArrowFunctionExpression || skipArrows === true && isArrow) {
+ return;
+ }
+
+ if (!typeAnnotation) {
+ context.report({
+ data: {
+ name: quoteName(parameterName)
+ },
+ message: 'Missing {{name}}parameter type annotation.',
+ node: identifierNode
+ });
+ }
+ });
+ };
+});
diff --git a/src/rules/requireReturnType.js b/src/rules/requireReturnType.js
new file mode 100644
index 0000000..47b255f
--- /dev/null
+++ b/src/rules/requireReturnType.js
@@ -0,0 +1,83 @@
+import _ from 'lodash';
+import {
+ isFlowFile
+} from './../utilities';
+
+export default (context) => {
+ const checkThisFile = !_.get(context, 'settings.flowtype.onlyFilesWithFlowAnnotation') || isFlowFile(context);
+
+ if (!checkThisFile) {
+ return () => {};
+ }
+
+ const annotateReturn = (_.get(context, 'options[0]') || 'always') === 'always';
+ const annotateUndefined = (_.get(context, 'options[1].annotateUndefined') || 'never') === 'always';
+ const skipArrows = _.get(context, 'options[1].excludeArrowFunctions') || false;
+
+ const targetNodes = [];
+
+ const registerFunction = (functionNode) => {
+ targetNodes.push({
+ functionNode
+ });
+ };
+
+ const isUndefinedReturnType = (returnNode) => {
+ return returnNode.argument === null || returnNode.argument.name === 'undefined' || returnNode.argument.operator === 'void';
+ };
+
+ const getIsReturnTypeAnnotationUndefined = (targetNode) => {
+ const isReturnTypeAnnotationLiteralUndefined = _.get(targetNode, 'functionNode.returnType.typeAnnotation.id.name') === 'undefined' && _.get(targetNode, 'functionNode.returnType.typeAnnotation.type') === 'GenericTypeAnnotation';
+ const isReturnTypeAnnotationVoid = _.get(targetNode, 'functionNode.returnType.typeAnnotation.type') === 'VoidTypeAnnotation';
+
+ return isReturnTypeAnnotationLiteralUndefined || isReturnTypeAnnotationVoid;
+ };
+
+ const evaluateFunction = (functionNode) => {
+ const targetNode = targetNodes.pop();
+
+ if (functionNode !== targetNode.functionNode) {
+ throw new Error('Mismatch.');
+ }
+
+ const isArrow = functionNode.type === 'ArrowFunctionExpression';
+ const isArrowFunctionExpression = functionNode.expression;
+ const hasImplicitReturnType = functionNode.async || functionNode.generator;
+ const isFunctionReturnUndefined = !isArrowFunctionExpression && !hasImplicitReturnType && (!targetNode.returnStatementNode || isUndefinedReturnType(targetNode.returnStatementNode));
+ const isReturnTypeAnnotationUndefined = getIsReturnTypeAnnotationUndefined(targetNode);
+
+ if (skipArrows === 'expressionsOnly' && isArrowFunctionExpression || skipArrows === true && isArrow) {
+ return;
+ }
+
+ if (isFunctionReturnUndefined && isReturnTypeAnnotationUndefined && !annotateUndefined) {
+ context.report(functionNode, 'Must not annotate undefined return type.');
+ } else if (isFunctionReturnUndefined && !isReturnTypeAnnotationUndefined && annotateUndefined) {
+ context.report(functionNode, 'Must annotate undefined return type.');
+ } else if (!isFunctionReturnUndefined && !isReturnTypeAnnotationUndefined) {
+ if (annotateReturn && !functionNode.returnType) {
+ context.report(functionNode, 'Missing return type annotation.');
+ }
+ }
+ };
+
+ const evaluateNoise = () => {
+ targetNodes.pop();
+ };
+
+ return {
+ ArrowFunctionExpression: registerFunction,
+ 'ArrowFunctionExpression:exit': evaluateFunction,
+ ClassDeclaration: registerFunction,
+ 'ClassDeclaration:exit': evaluateNoise,
+ ClassExpression: registerFunction,
+ 'ClassExpression:exit': evaluateNoise,
+ FunctionDeclaration: registerFunction,
+ 'FunctionDeclaration:exit': evaluateFunction,
+ FunctionExpression: registerFunction,
+ 'FunctionExpression:exit': evaluateFunction,
+ ReturnStatement: (node) => {
+ targetNodes[targetNodes.length - 1].returnStatementNode = node;
+ }
+ };
+};
diff --git a/src/rules/requireValidFileAnnotation.js b/src/rules/requireValidFileAnnotation.js
new file mode 100644
index 0000000..2087446
--- /dev/null
+++ b/src/rules/requireValidFileAnnotation.js
@@ -0,0 +1,66 @@
+import _ from 'lodash';
+import {
+ isFlowFile,
+ isFlowFileAnnotation
+} from './../utilities';
+
+const defaults = {
+ annotationStyle: 'none'
+};
+
+const looksLikeFlowFileAnnotation = (comment) => {
+ return /@(?:no)?flow/i.test(comment);
+};
+
+const isValidAnnotationStyle = (node, style) => {
+ if (style === 'none') {
+ return true;
+ }
+
+ return style === node.type.toLowerCase();
+};
+
+export const schema = [
+ {
+ enum: ['always']
+ }
+];
+
+export default (context) => {
+ const checkThisFile = !_.get(context, 'settings.flowtype.onlyFilesWithFlowAnnotation') || isFlowFile(context);
+
+ if (!checkThisFile) {
+ return {};
+ }
+
+ const always = context.options[0] === 'always';
+ const style = _.get(context, 'options[1].annotationStyle', defaults.annotationStyle);
+
+ return {
+ Program (node) {
+ const firstToken = node.tokens[0];
+
+ const potentialFlowFileAnnotation = _.find(context.getAllComments(), (comment) => {
+ return looksLikeFlowFileAnnotation(comment.value);
+ });
+
+ if (potentialFlowFileAnnotation) {
+ if (firstToken && firstToken.start < potentialFlowFileAnnotation.start) {
+ context.report(potentialFlowFileAnnotation, 'Flow file annotation not at the top of the file.');
+ }
+
+ if (!isFlowFileAnnotation(potentialFlowFileAnnotation.value)) {
+ context.report(potentialFlowFileAnnotation, 'Malformed flow file annotation.');
+ }
+
+ if (!isValidAnnotationStyle(potentialFlowFileAnnotation, style)) {
+ const str = style === 'line' ? '`// @flow`' : '`/* @flow */`';
+
+ context.report(potentialFlowFileAnnotation, 'Flow file annotation style must be ' + str);
+ }
+ } else if (always) {
+ context.report(node, 'Flow file annotation is missing.');
+ }
+ }
+ };
+};
diff --git a/src/rules/semi.js b/src/rules/semi.js
new file mode 100644
index 0000000..1dc6ddf
--- /dev/null
+++ b/src/rules/semi.js
@@ -0,0 +1,52 @@
+export default (context) => {
+ const never = (context.options[0] || 'always') === 'never';
+ const sourceCode = context.getSourceCode();
+
+ const report = (node, missing) => {
+ const lastToken = sourceCode.getLastToken(node);
+ let fix, message;
+ let {loc} = lastToken;
+
+ if (missing) {
+ message = 'Missing semicolon.';
+ loc = loc.end;
+ fix = (fixer) => {
+ return fixer.insertTextAfter(lastToken, ';');
+ };
+ } else {
+ message = 'Extra semicolon.';
+ loc = loc.start;
+ fix = (fixer) => {
+ return fixer.remove(lastToken);
+ };
+ }
+
+ context.report({
+ fix,
+ loc,
+ message,
+ node
+ });
+ };
+
+ const isSemicolon = (token) => {
+ return token.type === 'Punctuator' && token.value === ';';
+ };
+
+ const checkForSemicolon = (node) => {
+ const lastToken = sourceCode.getLastToken(node);
+ const isLastTokenSemicolon = isSemicolon(lastToken);
+
+ if (never && isLastTokenSemicolon) {
+ report(node, false);
+ }
+
+ if (!never && !isLastTokenSemicolon) {
+ report(node, true);
+ }
+ };
+
+ return {
+ TypeAlias: checkForSemicolon
+ };
+};
diff --git a/src/rules/sortKeys.js b/src/rules/sortKeys.js
new file mode 100644
index 0000000..43d2012
--- /dev/null
+++ b/src/rules/sortKeys.js
@@ -0,0 +1,91 @@
+import _ from 'lodash';
+import {
+ getParameterName
+} from './../utilities';
+
+const defaults = {
+ caseSensitive: true,
+ natural: false
+};
+
+/**
+ * Functions to compare the order of two strings
+ *
+ * Based on a similar function from eslint's sort-keys rule.
+ * https://github.com/eslint/eslint/blob/master/lib/rules/sort-keys.js
+ *
+ * @private
+ */
+const isValidOrders = {
+ asc (str1, str2) {
+ return str1 <= str2;
+ },
+ ascI (str1, str2) {
+ return str1.toLowerCase() <= str2.toLowerCase();
+ },
+ ascIN (str1, str2) {
+ return isValidOrders.naturalCompare(str1.toLowerCase(), str2.toLowerCase()) <= 0;
+ },
+ ascN (str1, str2) {
+ return isValidOrders.naturalCompare(str1, str2) <= 0;
+ },
+ desc (str1, str2) {
+ return isValidOrders.asc(str2, str1);
+ },
+ descI (str1, str2) {
+ return isValidOrders.ascI(str2, str1);
+ },
+ descIN (str1, str2) {
+ return isValidOrders.ascIN(str2, str1);
+ },
+ descN (str1, str2) {
+ return isValidOrders.ascN(str2, str1);
+ },
+ naturalCompare (str1, str2) {
+ return str1.localeCompare(str2, 'en-US', {numeric: true});
+ }
+};
+
+export default (context) => {
+ const order = _.get(context, ['options', 0], 'asc');
+ const {natural, caseSensitive} = _.get(context, ['options', 1], defaults);
+ const insensitive = caseSensitive === false;
+
+ let prev;
+ const checkKeyOrder = (node) => {
+ prev = null;
+
+ _.forEach(node.properties, (identifierNode) => {
+ const current = getParameterName(identifierNode, context);
+ const last = prev;
+
+ // keep track of the last token
+ prev = current || last;
+
+ if (!last || !current) {
+ return;
+ }
+
+ const isValidOrder = isValidOrders[order + (insensitive ? 'I' : '') + (natural ? 'N' : '')];
+
+ if (isValidOrder(last, current) === false) {
+ context.report({
+ data: {
+ current,
+ insensitive: insensitive ? 'insensitive ' : '',
+ last,
+ natural: natural ? 'natural ' : '',
+ order
+ },
+ loc: identifierNode.loc,
+ message: 'Expected type annotations to be in {{natural}}{{insensitive}}{{order}}ending order. "{{current}}" should be before "{{last}}".',
+ node: identifierNode
+ });
+ }
+ });
+ };
+
+ return {
+ ObjectTypeAnnotation: checkKeyOrder
+ };
+};
diff --git a/src/rules/spaceAfterTypeColon.js b/src/rules/spaceAfterTypeColon.js
new file mode 100644
index 0000000..d93b0c8
--- /dev/null
+++ b/src/rules/spaceAfterTypeColon.js
@@ -0,0 +1,7 @@
+import makeSpacing from './typeColonSpacing';
+
+export default (context) => {
+ return makeSpacing('after', context, {
+ always: (context.options[0] || 'always') === 'always'
+ });
+};
diff --git a/src/rules/spaceBeforeGenericBracket.js b/src/rules/spaceBeforeGenericBracket.js
new file mode 100644
index 0000000..f0902d0
--- /dev/null
+++ b/src/rules/spaceBeforeGenericBracket.js
@@ -0,0 +1,47 @@
+import {spacingFixers} from '../utilities';
+
+export default (context) => {
+ const never = (context.options[0] || 'never') === 'never';
+
+ return {
+ GenericTypeAnnotation (node) {
+ const types = node.typeParameters;
+
+ // Promise<foo>
+ // ^^^^^^^^^^^^ GenericTypeAnnotation (with typeParameters)
+ // ^^^ GenericTypeAnnotation (without typeParameters)
+ if (!types) {
+ return;
+ }
+
+ const spaceBefore = types.start - node.id.end;
+
+ if (never && spaceBefore) {
+ context.report({
+ data: {name: node.id.name},
+ fix: spacingFixers.stripSpacesAfter(node.id, spaceBefore),
+ message: 'There must be no space before "{{name}}" generic type annotation bracket',
+ node
+ });
+ }
+
+ if (!never && !spaceBefore) {
+ context.report({
+ data: {name: node.id.name},
+ fix: spacingFixers.addSpaceAfter(node.id),
+ message: 'There must be a space before "{{name}}" generic type annotation bracket',
+ node
+ });
+ }
+
+ if (!never && spaceBefore > 1) {
+ context.report({
+ data: {name: node.id.name},
+ fix: spacingFixers.stripSpacesAfter(node.id, spaceBefore - 1),
+ message: 'There must be one space before "{{name}}" generic type annotation bracket',
+ node
+ });
+ }
+ }
+ };
+};
diff --git a/src/rules/spaceBeforeTypeColon.js b/src/rules/spaceBeforeTypeColon.js
new file mode 100644
index 0000000..b199063
--- /dev/null
+++ b/src/rules/spaceBeforeTypeColon.js
@@ -0,0 +1,7 @@
+import makeSpacing from './typeColonSpacing';
+
+export default (context) => {
+ return makeSpacing('before', context, {
+ always: context.options[0] === 'always'
+ });
+};
diff --git a/src/rules/typeColonSpacing/evaluateFunctions.js b/src/rules/typeColonSpacing/evaluateFunctions.js
new file mode 100644
index 0000000..f6ccd5a
--- /dev/null
+++ b/src/rules/typeColonSpacing/evaluateFunctions.js
@@ -0,0 +1,14 @@
+import _ from 'lodash';
+import {iterateFunctionNodes} from '../../utilities';
+import evaluateTypical from './evaluateTypical';
+import evaluateReturnType from './evaluateReturnType';
+
+export default iterateFunctionNodes((context, report) => {
+ const checkParam = evaluateTypical(context, report, 'parameter');
+ const checkReturnType = evaluateReturnType(context, report);
+
+ return (functionNode) => {
+ _.forEach(functionNode.params, checkParam);
+ checkReturnType(functionNode);
+ };
+});
diff --git a/src/rules/typeColonSpacing/evaluateObjectTypeIndexer.js b/src/rules/typeColonSpacing/evaluateObjectTypeIndexer.js
new file mode 100644
index 0000000..914be1e
--- /dev/null
+++ b/src/rules/typeColonSpacing/evaluateObjectTypeIndexer.js
@@ -0,0 +1,21 @@
+import {getTokenAfterParens, getTokenBeforeParens} from '../../utilities';
+
+export default (context, report) => {
+ const sourceCode = context.getSourceCode();
+
+ return (objectTypeIndexer) => {
+ // type X = { [a: b]: c }
+ // ^
+ report({
+ colon: getTokenBeforeParens(sourceCode, objectTypeIndexer.key),
+ node: objectTypeIndexer
+ });
+
+ // type X = { [a: b]: c }
+ // ^
+ report({
+ colon: sourceCode.getTokenAfter(getTokenAfterParens(sourceCode, objectTypeIndexer.key)),
+ node: objectTypeIndexer
+ });
+ };
+};
diff --git a/src/rules/typeColonSpacing/evaluateObjectTypeProperty.js b/src/rules/typeColonSpacing/evaluateObjectTypeProperty.js
new file mode 100644
index 0000000..44af4f8
--- /dev/null
+++ b/src/rules/typeColonSpacing/evaluateObjectTypeProperty.js
@@ -0,0 +1,42 @@
+import {getParameterName, quoteName} from '../../utilities';
+
+const getColon = (context, objectTypeProperty) => {
+ let tokenIndex = 1; // eslint-disable-line init-declarations
+
+ if (objectTypeProperty.optional) {
+ tokenIndex++;
+ }
+
+ if (objectTypeProperty.static) {
+ tokenIndex++;
+ }
+
+ if (objectTypeProperty.variance) {
+ tokenIndex++;
+ }
+
+ return context.getSourceCode().getFirstToken(objectTypeProperty, tokenIndex);
+};
+
+// 1) type X = { foo(): A; }
+// 2) type X = { foo: () => A; }
+// the above have identical ASTs (save for their ranges)
+// case 1 doesn't have a type annotation colon and should be ignored
+const isShortPropertyFunction = (objectTypeProperty) => {
+ return objectTypeProperty.value.type === 'FunctionTypeAnnotation' && objectTypeProperty.start === objectTypeProperty.value.start;
+};
+
+export default (context, report) => {
+ return (objectTypeProperty) => {
+ if (isShortPropertyFunction(objectTypeProperty)) {
+ // potential difference: not checked in before
+ return;
+ }
+
+ report({
+ colon: getColon(context, objectTypeProperty),
+ name: quoteName(getParameterName(objectTypeProperty, context)),
+ node: objectTypeProperty
+ });
+ };
+};
diff --git a/src/rules/typeColonSpacing/evaluateReturnType.js b/src/rules/typeColonSpacing/evaluateReturnType.js
new file mode 100644
index 0000000..d1815fb
--- /dev/null
+++ b/src/rules/typeColonSpacing/evaluateReturnType.js
@@ -0,0 +1,16 @@
+export default (context, report) => {
+ const sourceCode = context.getSourceCode();
+
+ return (functionNode) => {
+ // skip FunctionTypeAnnotation, possibly another rule as it's an arrow, not a colon?
+ // (foo: number) => string
+ // ^^^^
+ if (functionNode.returnType && functionNode.type !== 'FunctionTypeAnnotation') {
+ report({
+ colon: sourceCode.getFirstToken(functionNode.returnType),
+ node: functionNode,
+ type: 'return type'
+ });
+ }
+ };
+};
diff --git a/src/rules/typeColonSpacing/evaluateTypeCastExpression.js b/src/rules/typeColonSpacing/evaluateTypeCastExpression.js
new file mode 100644
index 0000000..bf77f9f
--- /dev/null
+++ b/src/rules/typeColonSpacing/evaluateTypeCastExpression.js
@@ -0,0 +1,11 @@
+export default (context, report) => {
+ const sourceCode = context.getSourceCode();
+
+ return (typeCastExpression) => {
+ report({
+ colon: sourceCode.getFirstToken(typeCastExpression.typeAnnotation),
+ node: typeCastExpression,
+ type: 'type cast'
+ });
+ };
+};
diff --git a/src/rules/typeColonSpacing/evaluateTypical.js b/src/rules/typeColonSpacing/evaluateTypical.js
new file mode 100644
index 0000000..c2228d2
--- /dev/null
+++ b/src/rules/typeColonSpacing/evaluateTypical.js
@@ -0,0 +1,27 @@
+import _ from 'lodash';
+import {getParameterName, quoteName} from '../../utilities';
+
+export default (context, report, typeForMessage) => {
+ const sourceCode = context.getSourceCode();
+
+ const getColon = (node, typeAnnotation) => {
+ if (node.type === 'FunctionTypeParam') {
+ return sourceCode.getFirstToken(node, node.optional ? 2 : 1);
+ } else {
+ return sourceCode.getFirstToken(typeAnnotation);
+ }
+ };
+
+ return (node) => {
+ const typeAnnotation = _.get(node, 'typeAnnotation') || _.get(node, 'left.typeAnnotation');
+
+ if (typeAnnotation) {
+ report({
+ colon: getColon(node, typeAnnotation),
+ name: quoteName(getParameterName(node, context)),
+ node,
+ type: typeForMessage + ' type annotation'
+ });
+ }
+ };
+};
diff --git a/src/rules/typeColonSpacing/index.js b/src/rules/typeColonSpacing/index.js
new file mode 100644
index 0000000..2bfa3c2
--- /dev/null
+++ b/src/rules/typeColonSpacing/index.js
@@ -0,0 +1,18 @@
+import reporter from './reporter';
+import evaluateObjectTypeIndexer from './evaluateObjectTypeIndexer';
+import evaluateObjectTypeProperty from './evaluateObjectTypeProperty';
+import evaluateTypeCastExpression from './evaluateTypeCastExpression';
+import evaluateTypical from './evaluateTypical';
+import evaluateFunctions from './evaluateFunctions';
+
+export default (direction, context, options) => {
+ const report = reporter(direction, context, options);
+
+ return {
+ ...evaluateFunctions(context, report),
+ ClassProperty: evaluateTypical(context, report, 'class property'),
+ ObjectTypeIndexer: evaluateObjectTypeIndexer(context, report),
+ ObjectTypeProperty: evaluateObjectTypeProperty(context, report),
+ TypeCastExpression: evaluateTypeCastExpression(context, report)
+ };
+};
diff --git a/src/rules/typeColonSpacing/reporter.js b/src/rules/typeColonSpacing/reporter.js
new file mode 100644
index 0000000..5e17512
--- /dev/null
+++ b/src/rules/typeColonSpacing/reporter.js
@@ -0,0 +1,45 @@
+import {spacingFixers} from '../../utilities';
+
+const getSpaces = (direction, colon, context) => {
+ const sourceCode = context.getSourceCode();
+
+ if (direction === 'before') {
+ return colon.start - sourceCode.getTokenBefore(colon).end;
+ } else {
+ return sourceCode.getTokenAfter(colon).start - colon.end;
+ }
+};
+
+export default (direction, context, {always}) => {
+ return ({colon, node, name = '', type = 'type annotation'}) => {
+ const spaces = getSpaces(direction, colon, context);
+ const data = {
+ direction,
+ name,
+ type
+ };
+
+ if (always && spaces > 1) {
+ context.report({
+ data,
+ fix: spacingFixers.stripSpaces(direction, colon, spaces - 1),
+ message: 'There must be 1 space {{direction}} {{name}}{{type}} colon.',
+ node
+ });
+ } else if (always && spaces === 0) {
+ context.report({
+ data,
+ fix: spacingFixers.addSpace(direction, colon),
+ message: 'There must be a space {{direction}} {{name}}{{type}} colon.',
+ node
+ });
+ } else if (!always && spaces > 0) {
+ context.report({
+ data,
+ fix: spacingFixers.stripSpaces(direction, colon, spaces),
+ message: 'There must be no space {{direction}} {{name}}{{type}} colon.',
+ node
+ });
+ }
+ };
+};
diff --git a/src/rules/typeIdMatch.js b/src/rules/typeIdMatch.js
new file mode 100644
index 0000000..a3d5a8d
--- /dev/null
+++ b/src/rules/typeIdMatch.js
@@ -0,0 +1,22 @@
+export const schema = [
+ {
+ type: 'string'
+ }
+];
+
+export default (context) => {
+ const pattern = new RegExp(context.options[0] || '^([A-Z][a-z0-9]*)+Type$');
+
+ return {
+ TypeAlias (typeAliasNode) {
+ const typeIdentifierName = typeAliasNode.id.name;
+
+ if (!pattern.test(typeIdentifierName)) {
+ context.report(typeAliasNode, 'Type identifier \'{{name}}\' does not match pattern \'{{pattern}}\'.', {
+ name: typeIdentifierName,
+ pattern: pattern.toString()
+ });
+ }
+ }
+ };
+};
diff --git a/src/rules/unionIntersectionSpacing.js b/src/rules/unionIntersectionSpacing.js
new file mode 100644
index 0000000..5295798
--- /dev/null
+++ b/src/rules/unionIntersectionSpacing.js
@@ -0,0 +1,67 @@
+import {spacingFixers, getTokenAfterParens} from '../utilities';
+
+export default (context) => {
+ const sourceCode = context.getSourceCode();
+
+ const always = (context.options[0] || 'always') === 'always';
+
+ const check = (node) => {
+ node.types.forEach((type, index) => {
+ if (index + 1 === node.types.length) {
+ return;
+ }
+
+ const separator = getTokenAfterParens(sourceCode, type);
+ const endOfType = sourceCode.getTokenBefore(separator);
+ const nextType = sourceCode.getTokenAfter(separator);
+
+ const spaceBefore = separator.start - endOfType.end;
+ const spaceAfter = nextType.start - separator.end;
+
+ const data = {type: node.type === 'UnionTypeAnnotation' ? 'union' : 'intersection'};
+
+ if (always) {
+ if (!spaceBefore) {
+ context.report({
+ data,
+ fix: spacingFixers.addSpaceAfter(endOfType),
+ message: 'There must be a space before {{type}} type annotation separator',
+ node
+ });
+ }
+
+ if (!spaceAfter) {
+ context.report({
+ data,
+ fix: spacingFixers.addSpaceAfter(separator),
+ message: 'There must be a space after {{type}} type annotation separator',
+ node
+ });
+ }
+ } else {
+ if (spaceBefore) {
+ context.report({
+ data,
+ fix: spacingFixers.stripSpacesAfter(endOfType, spaceBefore),
+ message: 'There must be no space before {{type}} type annotation separator',
+ node
+ });
+ }
+
+ if (spaceAfter) {
+ context.report({
+ data,
+ fix: spacingFixers.stripSpacesAfter(separator, spaceAfter),
+ message: 'There must be no space after {{type}} type annotation separator',
+ node
+ });
+ }
+ }
+ });
+ };
+
+ return {
+ IntersectionTypeAnnotation: check,
+ UnionTypeAnnotation: check
+ };
+};
diff --git a/src/rules/useFlowType.js b/src/rules/useFlowType.js
new file mode 100644
index 0000000..947fc7e
--- /dev/null
+++ b/src/rules/useFlowType.js
@@ -0,0 +1,36 @@
+export const schema = [];
+
+export default (context) => {
+ const markTypeAsUsed = (node) => {
+ context.markVariableAsUsed(node.id.name);
+ };
+
+ return {
+ DeclareClass: markTypeAsUsed,
+ DeclareFunction: markTypeAsUsed,
+ DeclareModule: markTypeAsUsed,
+ DeclareVariable: markTypeAsUsed,
+ GenericTypeAnnotation (node) {
+ let typeId;
+ let scope;
+ let variable;
+
+ if (node.id.type === 'Identifier') {
+ typeId = node.id;
+ } else if (node.id.type === 'QualifiedTypeIdentifier') {
+ typeId = node.id;
+ do {
+ typeId = typeId.qualification;
+ } while (typeId.qualification);
+ }
+
+ for (scope = context.getScope(); scope; scope = scope.upper) {
+ variable = scope.set.get(typeId.name);
+ if (variable && variable.defs.length) {
+ context.markVariableAsUsed(typeId.name);
+ break;
+ }
+ }
+ }
+ };
+};
diff --git a/src/rules/validSyntax.js b/src/rules/validSyntax.js
new file mode 100644
index 0000000..4bf2c1d
--- /dev/null
+++ b/src/rules/validSyntax.js
@@ -0,0 +1,27 @@
+import _ from 'lodash';
+import {
+ getParameterName,
+ iterateFunctionNodes,
+ quoteName
+} from './../utilities';
+
+export default iterateFunctionNodes((context) => {
+ return (functionNode) => {
+ _.forEach(functionNode.params, (identifierNode) => {
+ const nodeType = _.get(identifierNode, 'type');
+ const isAssignmentPattern = nodeType === 'AssignmentPattern';
+ const hasTypeAnnotation = Boolean(_.get(identifierNode, 'typeAnnotation'));
+ const leftAnnotated = Boolean(_.get(identifierNode, 'left.typeAnnotation'));
+
+ if (isAssignmentPattern && hasTypeAnnotation && !leftAnnotated) {
+ context.report({
+ data: {
+ name: quoteName(getParameterName(identifierNode, context))
+ },
+ message: '{{name}}parameter type annotation must be placed on left-hand side of assignment.',
+ node: identifierNode
+ });
+ }
+ });
+ };
+});
diff --git a/src/utilities/getParameterName.js b/src/utilities/getParameterName.js
new file mode 100644
index 0000000..f341c63
--- /dev/null
+++ b/src/utilities/getParameterName.js
@@ -0,0 +1,52 @@
+import _ from 'lodash';
+
+export default (identifierNode, context) => {
+ if (_.has(identifierNode, 'name')) {
+ return identifierNode.name;
+ }
+
+ if (_.has(identifierNode, 'left.name')) {
+ return identifierNode.left.name;
+ }
+
+ if (_.has(identifierNode, 'key.name')) {
+ return identifierNode.key.name;
+ }
+
+ if (identifierNode.type === 'RestElement') {
+ return identifierNode.argument.name;
+ }
+
+ if (identifierNode.type === 'ObjectTypeProperty') {
+ let tokenIndex = 0; // eslint-disable-line init-declarations
+
+ if (identifierNode.static) {
+ tokenIndex++;
+ }
+
+ if (identifierNode.variance) {
+ tokenIndex++;
+ }
+
+ return context.getSourceCode().getFirstToken(identifierNode, tokenIndex).value;
+ }
+
+ if (identifierNode.type === 'FunctionTypeParam') {
+ return context.getSourceCode().getFirstToken(identifierNode).value;
+ }
+
+ if (identifierNode.type === 'ObjectPattern' || identifierNode.type === 'ArrayPattern') {
+ const text = context.getSourceCode().getText(identifierNode);
+
+ if (identifierNode.typeAnnotation) {
+ return text.replace(context.getSourceCode().getText(identifierNode.typeAnnotation), '').trim();
+ } else {
+ return text;
+ }
+ }
+ if (_.get(identifierNode, 'left.type') === 'ObjectPattern') {
+ return context.getSourceCode().getText(identifierNode.left);
+ }
+
+ return null;
+};
diff --git a/src/utilities/getTokenAfterParens.js b/src/utilities/getTokenAfterParens.js
new file mode 100644
index 0000000..c4d6f25
--- /dev/null
+++ b/src/utilities/getTokenAfterParens.js
@@ -0,0 +1,13 @@
+const getTokenAfterParens = (sourceCode, node) => {
+ let token;
+
+ token = sourceCode.getTokenAfter(node);
+
+ while (token.type === 'Punctuator' && token.value === ')') {
+ token = sourceCode.getTokenAfter(token);
+ }
+
+ return token;
+};
+
+export default getTokenAfterParens;
diff --git a/src/utilities/getTokenBeforeParens.js b/src/utilities/getTokenBeforeParens.js
new file mode 100644
index 0000000..1bd0417
--- /dev/null
+++ b/src/utilities/getTokenBeforeParens.js
@@ -0,0 +1,13 @@
+const getTokenBeforeParens = (sourceCode, node) => {
+ let token;
+
+ token = sourceCode.getTokenBefore(node);
+
+ while (token.type === 'Punctuator' && token.value === '(') {
+ token = sourceCode.getTokenBefore(token);
+ }
+
+ return token;
+};
+
+export default getTokenBeforeParens;
diff --git a/src/utilities/index.js b/src/utilities/index.js
new file mode 100644
index 0000000..3ef344d
--- /dev/null
+++ b/src/utilities/index.js
@@ -0,0 +1,10 @@
+'create index';
+
+export getParameterName from './getParameterName.js';
+export isFlowFile from './isFlowFile.js';
+export isFlowFileAnnotation from './isFlowFileAnnotation.js';
+export iterateFunctionNodes from './iterateFunctionNodes.js';
+export * as spacingFixers from './spacingFixers';
+export quoteName from './quoteName';
+export getTokenBeforeParens from './getTokenBeforeParens';
+export getTokenAfterParens from './getTokenAfterParens';
diff --git a/src/utilities/isFlowFile.js b/src/utilities/isFlowFile.js
new file mode 100644
index 0000000..73660ff
--- /dev/null
+++ b/src/utilities/isFlowFile.js
@@ -0,0 +1,13 @@
+import isFlowFileAnnotation from './isFlowFileAnnotation.js';
+
+export default (context) => {
+ const comments = context.getAllComments();
+
+ if (!comments.length) {
+ return false;
+ }
+
+ const firstComment = comments[0];
+
+ return isFlowFileAnnotation(firstComment.value);
+};
diff --git a/src/utilities/isFlowFileAnnotation.js b/src/utilities/isFlowFileAnnotation.js
new file mode 100644
index 0000000..ee4ed8a
--- /dev/null
+++ b/src/utilities/isFlowFileAnnotation.js
@@ -0,0 +1,13 @@
+import _ from 'lodash';
+
+const FLOW_MATCHER = /^@(?:no)?flow$/;
+
+export default (comment) => {
+ // eslint-disable-next-line flowtype/require-valid-file-annotation
+ // The flow parser splits comments with the following regex to look for the @flow flag.
+ // See https://github.com/facebook/flow/blob/a96249b93541f2f7bfebd8d62085bf7a75de02f2/src/parsing/docblock.ml#L39
+ return _.some(comment.split(/[ \t\r\n\\*/]+/), (commentPart) => {
+ return FLOW_MATCHER.test(commentPart);
+ });
+};
+
diff --git a/src/utilities/iterateFunctionNodes.js b/src/utilities/iterateFunctionNodes.js
new file mode 100644
index 0000000..c8e0988
--- /dev/null
+++ b/src/utilities/iterateFunctionNodes.js
@@ -0,0 +1,12 @@
+export default (iterator) => {
+ return (context, ...rest) => {
+ const nodeIterator = iterator(context, ...rest);
+
+ return {
+ ArrowFunctionExpression: nodeIterator,
+ FunctionDeclaration: nodeIterator,
+ FunctionExpression: nodeIterator,
+ FunctionTypeAnnotation: nodeIterator
+ };
+ };
+};
diff --git a/src/utilities/quoteName.js b/src/utilities/quoteName.js
new file mode 100644
index 0000000..2106d8f
--- /dev/null
+++ b/src/utilities/quoteName.js
@@ -0,0 +1,3 @@
+export default (name) => {
+ return name ? '"' + name + '" ' : '';
+};
diff --git a/src/utilities/spacingFixers.js b/src/utilities/spacingFixers.js
new file mode 100644
index 0000000..d2e2f41
--- /dev/null
+++ b/src/utilities/spacingFixers.js
@@ -0,0 +1,39 @@
+export const stripSpacesBefore = (node, spaces) => {
+ return (fixer) => {
+ return fixer.removeRange([node.start - spaces, node.start]);
+ };
+};
+
+export const stripSpacesAfter = (node, spaces) => {
+ return (fixer) => {
+ return fixer.removeRange([node.end, node.end + spaces]);
+ };
+};
+
+export const addSpaceBefore = (node) => {
+ return (fixer) => {
+ return fixer.insertTextBefore(node, ' ');
+ };
+};
+
+export const addSpaceAfter = (node) => {
+ return (fixer) => {
+ return fixer.insertTextAfter(node, ' ');
+ };
+};
+
+export const stripSpaces = (direction, node, spaces) => {
+ if (direction === 'before') {
+ return stripSpacesBefore(node, spaces);
+ } else {
+ return stripSpacesAfter(node, spaces);
+ }
+};
+
+export const addSpace = (direction, node) => {
+ if (direction === 'before') {
+ return addSpaceBefore(node);
+ } else {
+ return addSpaceAfter(node);
+ }
+};
diff --git a/tests/rules/assertions/booleanStyle.js b/tests/rules/assertions/booleanStyle.js
new file mode 100644
index 0000000..dac6fe7
--- /dev/null
+++ b/tests/rules/assertions/booleanStyle.js
@@ -0,0 +1,34 @@
+export default {
+ invalid: [
+ {
+ code: 'type X = bool',
+ errors: [{message: 'Use "boolean", not "bool"'}],
+ output: 'type X = boolean'
+ },
+ {
+ code: 'type X = bool',
+ errors: [{message: 'Use "boolean", not "bool"'}],
+ options: ['boolean'],
+ output: 'type X = boolean'
+ },
+ {
+ code: 'type X = boolean',
+ errors: [{message: 'Use "bool", not "boolean"'}],
+ options: ['bool'],
+ output: 'type X = bool'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = boolean'
+ },
+ {
+ code: 'type X = boolean',
+ options: ['boolean']
+ },
+ {
+ code: 'type X = bool',
+ options: ['bool']
+ }
+ ]
+};
diff --git a/tests/rules/assertions/defineFlowType.js b/tests/rules/assertions/defineFlowType.js
new file mode 100644
index 0000000..95893d3
--- /dev/null
+++ b/tests/rules/assertions/defineFlowType.js
@@ -0,0 +1,219 @@
+import {
+ RuleTester
+} from 'eslint';
+import noUndefRule from 'eslint/lib/rules/no-undef';
+
+const VALID_WITH_DEFINE_FLOW_TYPE = [
+ {
+ code: 'var a: AType',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'var a: AType; var b: AType',
+ errors: [
+ '\'AType\' is not defined.',
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'var a; (a: AType)',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'var a: AType<BType>',
+ errors: [
+ '\'AType\' is not defined.',
+ '\'BType\' is not defined.'
+ ]
+ },
+ {
+ code: 'type A = AType',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'function f(a: AType) {}',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'function f(a: AType.a) {}',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'function f(a: AType.a.b) {}',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'function f(a): AType {}; var a: AType',
+ errors: [
+ '\'AType\' is not defined.',
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'function f(a): AType {}',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'class C { a: AType }',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'class C { a: AType.a }',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'class C { a: AType.a.b }',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'class C implements AType {}',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'interface AType {}',
+ errors: [
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: '({ a: ({b() {}}: AType) })',
+ // `AType` appears twice in `globalScope.through` as distinct
+ // references, this may be a babel-eslint bug.
+ errors: [
+ '\'AType\' is not defined.',
+ '\'AType\' is not defined.'
+ ]
+ },
+ {
+ code: 'type X = {Y<AType>(): BType}',
+ errors: [
+ '\'AType\' is not defined.',
+ '\'BType\' is not defined.'
+ ]
+ },
+ {
+ code: 'interface AType<BType> {}',
+ errors: [
+ '\'AType\' is not defined.',
+ '\'BType\' is not defined.'
+ ]
+ }
+];
+
+const ALWAYS_INVALID = [
+ {
+ code: 'var a = b',
+ errors: [
+ '\'b\' is not defined.'
+ ]
+ },
+ {
+ code: 'function f(a = b) {}',
+ errors: [
+ '\'b\' is not defined.'
+ ]
+ },
+ {
+ code: 'class C extends b {}',
+ errors: [
+ '\'b\' is not defined.'
+ ]
+ },
+ {
+ code: 'class C { static S = b }',
+ errors: [
+ '\'b\' is not defined.'
+ ]
+ }
+];
+
+const ALWAYS_VALID = [
+ 'var a: string',
+ 'var a: Array',
+ 'var a: Array<string>',
+ 'type A = Array',
+ 'function f(a: string) {}',
+ 'function f(a): string {}',
+ 'class C { a: string }',
+ 'var AType = {}; class C { a: AType.a }',
+ 'declare module A { declare var a: AType }'
+];
+
+/**
+ * This rule is tested differently than the rest because `RuleTester` is
+ * designed to test rule reporting and define-flow-type doesn't report
+ * anything. define-flow-type suppresses reports from no-undef. So we're
+ * actually testing no-undef's reporting with define-flow-type enabled.
+ */
+{
+ const ruleTester = new RuleTester({
+ parser: 'babel-eslint'
+ });
+
+ ruleTester.run('no-under must not trigger an error in these cases', noUndefRule, {
+ invalid: [],
+ valid: ALWAYS_VALID
+ });
+}
+
+{
+ const ruleTester = new RuleTester({
+ parser: 'babel-eslint'
+ });
+
+ ruleTester.run('no-undef must trigger an error when define-flow-type is not used in these cases', noUndefRule, {
+ invalid: [
+ ...ALWAYS_INVALID,
+ ...VALID_WITH_DEFINE_FLOW_TYPE
+ ],
+ valid: []
+ });
+}
+
+export default {
+ invalid: [],
+ valid: [
+ ...VALID_WITH_DEFINE_FLOW_TYPE.map((subject) => {
+ return {
+ code: subject.code,
+ rules: {
+ 'no-undef': 2
+ }
+ };
+ }),
+ ...VALID_WITH_DEFINE_FLOW_TYPE.map((subject) => {
+ return {
+ code: subject.code,
+ rules: {
+ 'no-undef': 2,
+ 'no-use-before-define': [
+ 2,
+ 'nofunc'
+ ]
+ }
+ };
+ })
+ ]
+};
diff --git a/tests/rules/assertions/delimiterDangle.js b/tests/rules/assertions/delimiterDangle.js
new file mode 100644
index 0000000..f4f2344
--- /dev/null
+++ b/tests/rules/assertions/delimiterDangle.js
@@ -0,0 +1,512 @@
+const OBJECT_TYPE_ANNOTATION = {
+ invalid: [
+ {
+ code: 'type X = { foo: string, }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ output: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo: string, }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['never'],
+ output: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo: string; }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['never'],
+ output: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = {\nfoo: string,\n}',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['never'],
+ output: 'type X = {\nfoo: string\n}'
+ },
+ {
+ code: 'type X = { foo: string }',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always'],
+ output: 'type X = { foo: string, }'
+ },
+ {
+ code: 'type X = {\nfoo: string\n}',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always'],
+ output: 'type X = {\nfoo: string,\n}'
+ },
+ {
+ code: 'type X = { foo: string, }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = {\nfoo: string\n}',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = {\nfoo: string,\n}'
+ },
+ {
+ code: 'type X = { foo: string; }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['only-multiline'],
+ output: 'type X = { foo: string }'
+ },
+
+ // Only indexers...
+ {
+ code: 'type X = { [key: string]: number, }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['never'],
+ output: 'type X = { [key: string]: number }'
+ },
+ {
+ code: 'type X = { [key: string]: number }',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always'],
+ output: 'type X = { [key: string]: number, }'
+ },
+ {
+ code: 'type X = { [key: string]: number, }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = { [key: string]: number }'
+ },
+ {
+ code: 'type X = {\n[key: string]: number\n}',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = {\n[key: string]: number,\n}'
+ },
+ {
+ code: 'type X = { [key: string]: number; }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['only-multiline'],
+ output: 'type X = { [key: string]: number }'
+ },
+
+ // Indexer, Prop...
+ {
+ code: 'type X = { [key: string]: number, foo: string, }',
+ errors: [{
+ // be sure it's reporting the prop, not the indexer
+ column: 35,
+ line: 1,
+ message: 'Unexpected trailing delimiter'
+ }],
+ options: ['never'],
+ output: 'type X = { [key: string]: number, foo: string }'
+ },
+ {
+ code: 'type X = {\n[key: string]: number,\nfoo: string,\n}',
+ errors: [{
+ // be sure it's reporting the prop, not the indexer
+ column: 1,
+ line: 3,
+ message: 'Unexpected trailing delimiter'
+ }],
+ options: ['never'],
+ output: 'type X = {\n[key: string]: number,\nfoo: string\n}'
+ },
+ {
+ code: 'type X = {\n[key: string]: number,\naReallyLongPropertyNameHere: string,\n}',
+ errors: [{
+ // be sure it's reporting the prop, not the indexer
+ column: 1,
+ line: 3,
+ message: 'Unexpected trailing delimiter'
+ }],
+ options: ['never'],
+ output: 'type X = {\n[key: string]: number,\naReallyLongPropertyNameHere: string\n}'
+ },
+ {
+ code: 'type X = { [key: string]: number, foo: string }',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always'],
+ output: 'type X = { [key: string]: number, foo: string, }'
+ },
+ {
+ code: 'type X = {\n[key: string]: number;\nfoo: string\n}',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always'],
+ output: 'type X = {\n[key: string]: number;\nfoo: string,\n}'
+ },
+ {
+ code: 'type X = { [key: string]: number, foo: string, }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = { [key: string]: number, foo: string }'
+ },
+ {
+ code: 'type X = {\n[key: string]: number,\nfoo: string\n}',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = {\n[key: string]: number,\nfoo: string,\n}'
+ },
+ {
+ code: 'type X = { [key: string]: number, foo: string, }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['only-multiline'],
+ output: 'type X = { [key: string]: number, foo: string }'
+ },
+
+ // Prop, Indexer...
+ {
+ code: 'type X = { foo: string, [key: string]: number, }',
+ errors: [{
+ // be sure it's reporting the indexer, not the prop
+ column: 25,
+ line: 1,
+ message: 'Unexpected trailing delimiter'
+ }],
+ options: ['never'],
+ output: 'type X = { foo: string, [key: string]: number }'
+ },
+ {
+ code: 'type X = {\nfoo: string,\n[key: string]: number,\n}',
+ errors: [{
+ // be sure it's reporting the prop, not the indexer
+ column: 1,
+ line: 3,
+ message: 'Unexpected trailing delimiter'
+ }],
+ options: ['never'],
+ output: 'type X = {\nfoo: string,\n[key: string]: number\n}'
+ },
+ {
+ code: 'type X = {\naReallyLongPropertyNameHere: string,\n[key: string]: number,\n}',
+ errors: [{
+ // be sure it's reporting the prop, not the indexer
+ column: 1,
+ line: 3,
+ message: 'Unexpected trailing delimiter'
+ }],
+ options: ['never'],
+ output: 'type X = {\naReallyLongPropertyNameHere: string,\n[key: string]: number\n}'
+ },
+ {
+ code: 'type X = { foo: string, [key: string]: number }',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always'],
+ output: 'type X = { foo: string, [key: string]: number, }'
+ },
+ {
+ code: 'type X = { foo: string; [key: string]: number }',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always'],
+ output: 'type X = { foo: string; [key: string]: number, }'
+ },
+ {
+ code: 'type X = { foo: string, [key: string]: number; }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = { foo: string, [key: string]: number }'
+ },
+ {
+ code: 'type X = {\nfoo: string,\n[key: string]: number\n}',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = {\nfoo: string,\n[key: string]: number,\n}'
+ },
+ {
+ code: 'type X = { foo: string, [key: string]: number; }',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['only-multiline'],
+ output: 'type X = { foo: string, [key: string]: number }'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo: string }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { foo: string, }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { foo: string; }',
+ options: ['always']
+ },
+ {
+ code: 'type X = {\nfoo: string\n}',
+ options: ['never']
+ },
+ {
+ code: 'type X = {\nfoo: string,\n}',
+ options: ['always']
+ },
+ {
+ code: 'type X = { foo: string }',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = {\nfoo: string,\n}',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = {\nfoo: string;\n}',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = { foo: string }',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = {\nfoo: string\n}',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = {\nfoo: string,\n}',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = {\nfoo: string;\n}',
+ options: ['only-multiline']
+ },
+
+ // Empty...
+ {
+ code: 'type X = {}',
+ options: ['never']
+ },
+ {
+ code: 'type X = {}',
+ options: ['always']
+ },
+ {
+ code: 'type X = {}',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = {}',
+ options: ['only-multiline']
+ },
+
+ // Only indexers...
+ {
+ code: 'type X = { [key: string]: number }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { [key: string]: number, }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { [key: string]: number; }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { [key: string]: number }',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = {\n[key: string]: number,\n}',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = {\n[key: string]: number,\n}',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = {\n[key: string]: number\n}',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = { [key: string]: number }',
+ options: ['only-multiline']
+ },
+
+ // Indexer, Prop...
+ {
+ code: 'type X = { [key: string]: number, foo: string }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { [key: string]: number, foo: string, }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { [key: string]: number; foo: string; }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { [key: string]: number, foo: string }',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = {\n[key: string]: number,\nfoo: string,\n}',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = {\n[key: string]: number,\nfoo: string,\n}',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = {\n[key: string]: number;\nfoo: string\n}',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = { [key: string]: number, foo: string }',
+ options: ['only-multiline']
+ },
+
+ // Prop, Indexer...
+ {
+ code: 'type X = { foo: string, [key: string]: number }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { foo: string, [key: string]: number, }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { foo: string; [key: string]: number; }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { foo: string, [key: string]: number }',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = {\nfoo: string,\n[key: string]: number,\n}',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = {\nfoo: string,\n[key: string]: number,\n}',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = {\nfoo: string;\n[key: string]: number\n}',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = { foo: string, [key: string]: number }',
+ options: ['only-multiline']
+ }
+ ]
+};
+
+const TUPLE_TYPE_ANNOTATION = {
+ invalid: [
+ {
+ code: 'type X = [string, number,]',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ output: 'type X = [string, number]'
+ },
+ {
+ code: 'type X = [string, number,]',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['never'],
+ output: 'type X = [string, number]'
+ },
+ {
+ code: 'type X = [\nstring,\nnumber,\n]',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['never'],
+ output: 'type X = [\nstring,\nnumber\n]'
+ },
+ {
+ code: 'type X = [string, number]',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always'],
+ output: 'type X = [string, number,]'
+ },
+ {
+ code: 'type X = [\nstring,\nnumber\n]',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always'],
+ output: 'type X = [\nstring,\nnumber,\n]'
+ },
+ {
+ code: 'type X = [string, number,]',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = [string, number]'
+ },
+ {
+ code: 'type X = [\nfoo, string\n]',
+ errors: [{message: 'Missing trailing delimiter'}],
+ options: ['always-multiline'],
+ output: 'type X = [\nfoo, string,\n]'
+ },
+ {
+ code: 'type X = [ number, string, ]',
+ errors: [{message: 'Unexpected trailing delimiter'}],
+ options: ['only-multiline'],
+ output: 'type X = [ number, string ]'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = [string, number]'
+ },
+ {
+ code: 'type X = [string, number]',
+ options: ['never']
+ },
+ {
+ code: 'type X = [\nstring,\nnumber\n]',
+ options: ['never']
+ },
+ {
+ code: 'type X = [string, number,]',
+ options: ['always']
+ },
+ {
+ code: 'type X = [\nstring,\nnumber,\n]',
+ options: ['always']
+ },
+ {
+ code: 'type X = [ foo, string ]',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = [\nfoo, string,\n]',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = [ number, string ]',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = [\nnumber,\nstring\n]',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = [\nnumber,\nstring,\n]',
+ options: ['only-multiline']
+ },
+ {
+ code: 'type X = []',
+ options: ['never']
+ },
+ {
+ code: 'type X = []',
+ options: ['always']
+ },
+ {
+ code: 'type X = []',
+ options: ['always-multiline']
+ },
+ {
+ code: 'type X = []',
+ options: ['only-multiline']
+ }
+ ]
+};
+
+export default {
+ invalid: [
+ ...OBJECT_TYPE_ANNOTATION.invalid,
+ ...TUPLE_TYPE_ANNOTATION.invalid
+ ],
+ valid: [
+ ...OBJECT_TYPE_ANNOTATION.valid,
+ ...TUPLE_TYPE_ANNOTATION.valid
+ ]
+};
diff --git a/tests/rules/assertions/genericSpacing.js b/tests/rules/assertions/genericSpacing.js
new file mode 100644
index 0000000..727f5bb
--- /dev/null
+++ b/tests/rules/assertions/genericSpacing.js
@@ -0,0 +1,117 @@
+export default {
+ invalid: [
+ // Never
+
+ {
+ code: 'type X = Promise< string>',
+ errors: [{message: 'There must be no space at start of "Promise" generic type annotation'}],
+ output: 'type X = Promise<string>'
+ },
+ {
+ code: 'type X = Promise< string>',
+ errors: [{message: 'There must be no space at start of "Promise" generic type annotation'}],
+ options: ['never'],
+ output: 'type X = Promise<string>'
+ },
+ {
+ code: 'type X = FooBar<string >',
+ errors: [{message: 'There must be no space at end of "FooBar" generic type annotation'}],
+ output: 'type X = FooBar<string>'
+ },
+ {
+ code: 'type X = Promise< string >',
+ errors: [
+ {message: 'There must be no space at start of "Promise" generic type annotation'},
+ {message: 'There must be no space at end of "Promise" generic type annotation'}
+ ],
+ output: 'type X = Promise<string>'
+ },
+ {
+ code: 'type X = Promise< (foo), bar, (((baz))) >',
+ errors: [
+ {message: 'There must be no space at start of "Promise" generic type annotation'},
+ {message: 'There must be no space at end of "Promise" generic type annotation'}
+ ],
+ output: 'type X = Promise<(foo), bar, (((baz)))>'
+ },
+
+ // Always (given no space)
+
+ {
+ code: 'type X = Promise<string >',
+ errors: [{message: 'There must be a space at start of "Promise" generic type annotation'}],
+ options: ['always'],
+ output: 'type X = Promise< string >'
+ },
+ {
+ code: 'type X = FooBar< string>',
+ errors: [{message: 'There must be a space at end of "FooBar" generic type annotation'}],
+ options: ['always'],
+ output: 'type X = FooBar< string >'
+ },
+ {
+ code: 'type X = Promise<string>',
+ errors: [
+ {message: 'There must be a space at start of "Promise" generic type annotation'},
+ {message: 'There must be a space at end of "Promise" generic type annotation'}
+ ],
+ options: ['always'],
+ output: 'type X = Promise< string >'
+ },
+ {
+ code: 'type X = Promise<(foo), bar, (((baz)))>',
+ errors: [
+ {message: 'There must be a space at start of "Promise" generic type annotation'},
+ {message: 'There must be a space at end of "Promise" generic type annotation'}
+ ],
+ options: ['always'],
+ output: 'type X = Promise< (foo), bar, (((baz))) >'
+ },
+
+ // Always (given too many spaces)
+
+ {
+ code: 'type X = FooBar< string >',
+ errors: [{message: 'There must be one space at start of "FooBar" generic type annotation'}],
+ options: ['always'],
+ output: 'type X = FooBar< string >'
+ },
+ {
+ code: 'type X = FooBar< string >',
+ errors: [{message: 'There must be one space at end of "FooBar" generic type annotation'}],
+ options: ['always'],
+ output: 'type X = FooBar< string >'
+ },
+ {
+ code: 'type X = Promise< (foo), bar, (((baz))) >',
+ errors: [
+ {message: 'There must be one space at start of "Promise" generic type annotation'},
+ {message: 'There must be one space at end of "Promise" generic type annotation'}
+ ],
+ options: ['always'],
+ output: 'type X = Promise< (foo), bar, (((baz))) >'
+ }
+ ],
+ valid: [
+ // Never
+
+ {code: 'type X = Promise<string>'},
+ {code: 'type X = Promise<(string)>'},
+ {code: 'type X = Promise<(foo), bar, (((baz)))>'},
+
+ // Always
+
+ {
+ code: 'type X = Promise< string >',
+ options: ['always']
+ },
+ {
+ code: 'type X = Promise< (string) >',
+ options: ['always']
+ },
+ {
+ code: 'type X = Promise< (foo), bar, (((baz))) >',
+ options: ['always']
+ }
+ ]
+};
diff --git a/tests/rules/assertions/noDupeKeys.js b/tests/rules/assertions/noDupeKeys.js
new file mode 100644
index 0000000..717ade5
--- /dev/null
+++ b/tests/rules/assertions/noDupeKeys.js
@@ -0,0 +1,17 @@
+export default {
+ invalid: [
+ {
+ code: 'type FooType = { a: number, b: string, a: number }',
+ errors: [{message: 'Duplicate property.'}]
+ },
+ {
+ code: 'type FooType = { a: number, b: string, a: string }',
+ errors: [{message: 'Duplicate property.'}]
+ }
+ ],
+ valid: [
+ {
+ code: 'type FooType = { a: number, b: string, c: number }'
+ }
+ ]
+};
diff --git a/tests/rules/assertions/noWeakTypes.js b/tests/rules/assertions/noWeakTypes.js
new file mode 100644
index 0000000..ce8c933
--- /dev/null
+++ b/tests/rules/assertions/noWeakTypes.js
@@ -0,0 +1,251 @@
+export default {
+ invalid: [
+ {
+ code: 'function foo(thing): any {}',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: 'function foo(thing): Promise<any> {}',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: 'function foo(thing): Promise<Promise<any>> {}',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: 'function foo(thing): Object {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Object"'
+ }]
+ },
+ {
+ code: 'function foo(thing): Promise<Object> {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Object"'
+ }]
+ },
+ {
+ code: 'function foo(thing): Promise<Promise<Object>> {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Object"'
+ }]
+ },
+ {
+ code: 'function foo(thing): Function {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Function"'
+ }]
+ },
+ {
+ code: 'function foo(thing): Promise<Function> {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Function"'
+ }]
+ },
+ {
+ code: 'function foo(thing): Promise<Promise<Function>> {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Function"'
+ }]
+ },
+ {
+ code: '(foo: any) => {}',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: '(foo: Function) => {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Function"'
+ }]
+ },
+ {
+ code: '(foo?: any) => {}',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: '(foo?: Function) => {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Function"'
+ }]
+ },
+ {
+ code: '(foo: { a: any }) => {}',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: '(foo: { a: Object }) => {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Object"'
+ }]
+ },
+ {
+ code: '(foo: any[]) => {}',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: 'type Foo = any',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: 'type Foo = Function',
+ errors: [{
+ message: 'Unexpected use of weak type "Function"'
+ }]
+ },
+ {
+ code: 'type Foo = { a: any }',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: 'type Foo = { a: Object }',
+ errors: [{
+ message: 'Unexpected use of weak type "Object"'
+ }]
+ },
+ {
+ code: 'type Foo = { (a: Object): string }',
+ errors: [{
+ message: 'Unexpected use of weak type "Object"'
+ }]
+ },
+ {
+ code: 'type Foo = { (a: string): Function }',
+ errors: [{
+ message: 'Unexpected use of weak type "Function"'
+ }]
+ },
+ {
+ code: 'function foo(thing: any) {}',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: 'function foo(thing: Object) {}',
+ errors: [{
+ message: 'Unexpected use of weak type "Object"'
+ }]
+ },
+ {
+ code: 'var foo: Function',
+ errors: [{
+ message: 'Unexpected use of weak type "Function"'
+ }]
+ },
+ {
+ code: 'var foo: Object',
+ errors: [{
+ message: 'Unexpected use of weak type "Object"'
+ }]
+ },
+ {
+ code: 'class Foo { props: any }',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: 'class Foo { props: Object }',
+ errors: [{
+ message: 'Unexpected use of weak type "Object"'
+ }]
+ },
+ {
+ code: 'var foo: any',
+ errors: [{
+ message: 'Unexpected use of weak type "any"'
+ }]
+ },
+ {
+ code: 'type X = any; type Y = Function; type Z = Object',
+ errors: [
+ {message: 'Unexpected use of weak type "any"'},
+ {message: 'Unexpected use of weak type "Object"'}
+ ],
+ options: [{
+ Function: false
+ }]
+ },
+ {
+ code: 'type X = any; type Y = Function; type Z = Object',
+ errors: [{message: 'Unexpected use of weak type "Function"'}],
+ options: [{
+ Object: false,
+ any: false
+ }]
+ }
+ ],
+ valid: [
+ {
+ code: 'function foo(thing): string {}'
+ },
+ {
+ code: 'function foo(thing): Promise<string> {}'
+ },
+ {
+ code: 'function foo(thing): Promise<Promise<string>> {}'
+ },
+ {
+ code: '(foo?: string) => {}'
+ },
+ {
+ code: '(foo: ?string) => {}'
+ },
+ {
+ code: '(foo: { a: string }) => {}'
+ },
+ {
+ code: '(foo: { a: ?string }) => {}'
+ },
+ {
+ code: '(foo: string[]) => {}'
+ },
+ {
+ code: 'type Foo = string'
+ },
+ {
+ code: 'type Foo = { a: string }'
+ },
+ {
+ code: 'type Foo = { (a: string): string }'
+ },
+ {
+ code: 'function foo(thing: string) {}'
+ },
+ {
+ code: 'var foo: string'
+ },
+ {
+ code: 'class Foo { props: string }'
+ },
+ {
+ code: 'type X = any; type Y = Object',
+ options: [{
+ Object: false,
+ any: false
+ }]
+ },
+ {
+ code: 'type X = Function',
+ options: [{Function: false}]
+ }
+ ]
+};
diff --git a/tests/rules/assertions/objectTypeDelimiter.js b/tests/rules/assertions/objectTypeDelimiter.js
new file mode 100644
index 0000000..90d0498
--- /dev/null
+++ b/tests/rules/assertions/objectTypeDelimiter.js
@@ -0,0 +1,147 @@
+export default {
+ invalid: [
+ {
+ code: 'type Foo = { a: Foo, b: Bar }',
+ errors: [{message: 'Prefer semicolons to commas in object and class types'}],
+ options: ['semicolon'],
+ output: 'type Foo = { a: Foo; b: Bar }'
+ },
+ {
+ code: 'type Foo = { a: Foo; b: Bar }',
+ errors: [{message: 'Prefer commas to semicolons in object and class types'}],
+ options: ['comma'],
+ output: 'type Foo = { a: Foo, b: Bar }'
+ },
+ {
+ code: 'type Foo = { [a: string]: Foo, [b: string]: Bar }',
+ errors: [{message: 'Prefer semicolons to commas in object and class types'}],
+ options: ['semicolon'],
+ output: 'type Foo = { [a: string]: Foo; [b: string]: Bar }'
+ },
+ {
+ code: 'type Foo = { [a: string]: Foo; [b: string]: Bar }',
+ errors: [{message: 'Prefer commas to semicolons in object and class types'}],
+ options: ['comma'],
+ output: 'type Foo = { [a: string]: Foo, [b: string]: Bar }'
+ },
+ {
+ code: 'type Foo = { (): Foo, (): Bar }',
+ errors: [{message: 'Prefer semicolons to commas in object and class types'}],
+ options: ['semicolon'],
+ output: 'type Foo = { (): Foo; (): Bar }'
+ },
+ {
+ code: 'type Foo = { (): Foo; (): Bar }',
+ errors: [{message: 'Prefer commas to semicolons in object and class types'}],
+ options: ['comma'],
+ output: 'type Foo = { (): Foo, (): Bar }'
+ },
+ {
+ code: 'declare class Foo { a: Foo, }',
+ errors: [{message: 'Prefer semicolons to commas in object and class types'}],
+ options: ['semicolon'],
+ output: 'declare class Foo { a: Foo; }'
+ },
+ {
+ code: 'declare class Foo { a: Foo; }',
+ errors: [{message: 'Prefer commas to semicolons in object and class types'}],
+ options: ['comma'],
+ output: 'declare class Foo { a: Foo, }'
+ },
+ {
+ code: 'declare class Foo { [a: string]: Foo, }',
+ errors: [{message: 'Prefer semicolons to commas in object and class types'}],
+ options: ['semicolon'],
+ output: 'declare class Foo { [a: string]: Foo; }'
+ },
+ {
+ code: 'declare class Foo { a: Foo; }',
+ errors: [{message: 'Prefer commas to semicolons in object and class types'}],
+ options: ['comma'],
+ output: 'declare class Foo { a: Foo, }'
+ },
+ {
+ code: 'declare class Foo { (): Foo, }',
+ errors: [{message: 'Prefer semicolons to commas in object and class types'}],
+ options: ['semicolon'],
+ output: 'declare class Foo { (): Foo; }'
+ },
+ {
+ code: 'declare class Foo { (): Foo; }',
+ errors: [{message: 'Prefer commas to semicolons in object and class types'}],
+ options: ['comma'],
+ output: 'declare class Foo { (): Foo, }'
+ },
+ {
+ code: 'declare class Foo { static (): Foo, }',
+ errors: [{message: 'Prefer semicolons to commas in object and class types'}],
+ options: ['semicolon'],
+ output: 'declare class Foo { static (): Foo; }'
+ },
+ {
+ code: 'declare class Foo { static (): Foo; }',
+ errors: [{message: 'Prefer commas to semicolons in object and class types'}],
+ options: ['comma'],
+ output: 'declare class Foo { static (): Foo, }'
+ }
+ ],
+ valid: [
+ {
+ code: 'type Foo = { a: Foo; b: Bar }',
+ options: ['semicolon']
+ },
+ {
+ code: 'type Foo = { a: Foo, b: Bar }',
+ options: ['comma']
+ },
+ {
+ code: 'type Foo = { [a: string]: Foo; [b: string]: Bar }',
+ options: ['semicolon']
+ },
+ {
+ code: 'type Foo = { [a: string]: Foo, [b: string]: Bar }',
+ options: ['comma']
+ },
+ {
+ code: 'type Foo = { (): Foo; (): Bar }',
+ options: ['semicolon']
+ },
+ {
+ code: 'type Foo = { (): Foo, (): Bar }',
+ options: ['comma']
+ },
+ {
+ code: 'type Foo = { a: Foo, b: Bar }'
+ },
+ {
+ code: 'type Foo = { [a: string]: Foo, [b: string]: Bar }'
+ },
+ {
+ code: 'type Foo = { (): Foo, (): Bar }'
+ },
+ {
+ code: 'declare class Foo { a: Foo; }',
+ options: ['semicolon']
+ },
+ {
+ code: 'declare class Foo { a: Foo, }',
+ options: ['comma']
+ },
+ {
+ code: 'declare class Foo { [a: string]: Foo; }',
+ options: ['semicolon']
+ },
+ {
+ code: 'declare class Foo { [a: string]: Foo, }',
+ options: ['comma']
+ },
+ {
+ code: 'declare class Foo { (): Foo; }',
+ options: ['semicolon']
+ },
+ {
+ code: 'declare class Foo { (): Foo, }',
+ options: ['comma']
+ }
+ ]
+};
diff --git a/tests/rules/assertions/requireParameterType.js b/tests/rules/assertions/requireParameterType.js
new file mode 100644
index 0000000..cbc25f2
--- /dev/null
+++ b/tests/rules/assertions/requireParameterType.js
@@ -0,0 +1,195 @@
+export default {
+ invalid: [
+ {
+ code: '(foo) => {}',
+ errors: [
+ {
+ message: 'Missing "foo" parameter type annotation.'
+ }
+ ]
+ },
+ {
+ code: 'function x(foo) {}',
+ errors: [
+ {
+ message: 'Missing "foo" parameter type annotation.'
+ }
+ ]
+ },
+ {
+ code: 'function x(foo) {}',
+ errors: [
+ {
+ message: 'Missing "foo" parameter type annotation.'
+ }
+ ],
+ options: [
+ {
+ excludeArrowFunctions: true
+ }
+ ]
+ },
+ {
+ code: '(foo = \'FOO\') => {}',
+ errors: [
+ {
+ message: 'Missing "foo" parameter type annotation.'
+ }
+ ]
+ },
+ {
+ code: '(...foo) => {}',
+ errors: [
+ {
+ message: 'Missing "foo" parameter type annotation.'
+ }
+ ]
+ },
+ {
+ code: '({foo}) => {}',
+ errors: [
+ {
+ message: 'Missing "{foo}" parameter type annotation.'
+ }
+ ]
+ },
+ {
+ code: '([foo]) => {}',
+ errors: [
+ {
+ message: 'Missing "[foo]" parameter type annotation.'
+ }
+ ]
+ },
+ {
+ code: '({foo = 1} = {}) => {}',
+ errors: [
+ {
+ message: 'Missing "{foo = 1}" parameter type annotation.'
+ }
+ ]
+ },
+ {
+ code: '// @flow\n(foo) => {}',
+ errors: [
+ {
+ message: 'Missing "foo" parameter type annotation.'
+ }
+ ],
+ settings: {
+ flowtype: {
+ onlyFilesWithFlowAnnotation: true
+ }
+ }
+ },
+ {
+ code: '(foo) => {}',
+ errors: [
+ {
+ message: 'Missing "foo" parameter type annotation.'
+ }
+ ],
+ options: [
+ {
+ excludeArrowFunctions: 'expressionsOnly'
+ }
+ ]
+ },
+ {
+ code: 'function x(foo) {}',
+ errors: [
+ {
+ message: 'Missing "foo" parameter type annotation.'
+ }
+ ],
+ options: [
+ {
+ excludeArrowFunctions: 'expressionsOnly'
+ }
+ ]
+ },
+ {
+ code: '(_foo: number, bar) => {}',
+ errors: [
+ {
+ message: 'Missing "bar" parameter type annotation.'
+ }
+ ],
+ options: [
+ {
+ excludeParameterMatch: '^_'
+ }
+ ]
+ },
+ {
+ code: '(_foo, bar) => {}',
+ errors: [
+ {
+ message: 'Missing "bar" parameter type annotation.'
+ }
+ ],
+ options: [
+ {
+ excludeParameterMatch: '^_'
+ }
+ ]
+ }
+ ],
+ valid: [
+ {
+ code: '(foo: string) => {}'
+ },
+ {
+ code: '(foo: string = \'FOO\') => {}'
+ },
+ {
+ code: '(...foo: string) => {}'
+ },
+ {
+ code: '({foo}: {foo: string}) => {}'
+ },
+ {
+ code: '([foo]: Array) => {}'
+ },
+ {
+ code: '(foo) => {}',
+ settings: {
+ flowtype: {
+ onlyFilesWithFlowAnnotation: true
+ }
+ }
+ },
+ {
+ code: '(foo) => {}',
+ options: [
+ {
+ excludeArrowFunctions: true
+ }
+ ]
+ },
+ {
+ code: '(foo) => 3',
+ options: [
+ {
+ excludeArrowFunctions: 'expressionsOnly'
+ }
+ ]
+ },
+ {
+ code: '(_foo, bar: string) => {}',
+ options: [
+ {
+ excludeParameterMatch: '^_'
+ }
+ ]
+ },
+ {
+ code: '(_foo: number, bar: string) => {}',
+ options: [
+ {
+ excludeParameterMatch: '^_'
+ }
+ ]
+ }
+ ]
+};
diff --git a/tests/rules/assertions/requireReturnType.js b/tests/rules/assertions/requireReturnType.js
new file mode 100644
index 0000000..77c1246
--- /dev/null
+++ b/tests/rules/assertions/requireReturnType.js
@@ -0,0 +1,476 @@
+export default {
+ invalid: [
+ {
+ code: '(foo) => { return "foo"; }',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ]
+ },
+ {
+ code: '(foo) => { return "foo"; }',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ options: [
+ 'always'
+ ]
+ },
+ {
+ code: '(foo) => "foo"',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ options: [
+ 'always'
+ ]
+ },
+ {
+ code: '(foo) => ({})',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ]
+ },
+ {
+ code: '(foo): undefined => { return; }',
+ errors: [
+ {
+ message: 'Must not annotate undefined return type.'
+ }
+ ]
+ },
+ {
+ code: '(foo): void => { return; }',
+ errors: [
+ {
+ message: 'Must not annotate undefined return type.'
+ }
+ ]
+ },
+ {
+ code: '(foo): undefined => { return undefined; }',
+ errors: [
+ {
+ message: 'Must not annotate undefined return type.'
+ }
+ ]
+ },
+ {
+ code: '(foo): void => { return void 0; }',
+ errors: [
+ {
+ message: 'Must not annotate undefined return type.'
+ }
+ ]
+ },
+ {
+ code: '(foo): undefined => { return; }',
+ errors: [
+ {
+ message: 'Must not annotate undefined return type.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'never'
+ }
+ ]
+ },
+ {
+ code: '(foo): void => { return; }',
+ errors: [
+ {
+ message: 'Must not annotate undefined return type.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'never'
+ }
+ ]
+ },
+ {
+ code: '(foo) => { return; }',
+ errors: [
+ {
+ message: 'Must annotate undefined return type.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: '(foo): undefined => { return undefined; }',
+ errors: [
+ {
+ message: 'Must not annotate undefined return type.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'never'
+ }
+ ]
+ },
+ {
+ code: '(foo) => { return undefined; }',
+ errors: [
+ {
+ message: 'Must annotate undefined return type.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: '(foo) => { return void 0; }',
+ errors: [
+ {
+ message: 'Must annotate undefined return type.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: '// @flow\n(foo) => { return 1; }',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ settings: {
+ flowtype: {
+ onlyFilesWithFlowAnnotation: true
+ }
+ }
+ },
+ {
+ code: '// @flow\n (foo) => { return undefined; }',
+ errors: [
+ {
+ message: 'Must annotate undefined return type.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ],
+ settings: {
+ flowtype: {
+ onlyFilesWithFlowAnnotation: true
+ }
+ }
+ },
+ {
+ code: 'async () => { return 2; }',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ options: [
+ 'always'
+ ]
+ },
+ {
+ code: 'async () => {}',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: 'async function x() {}',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: 'async () => { return; }',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ options: [
+ 'always'
+ ]
+ },
+ {
+ code: 'function* x() {}',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ options: [
+ 'always'
+ ]
+ },
+ {
+ code: '() => { return 3; }',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ excludeArrowFunctions: 'expressionsOnly'
+ }
+ ]
+ },
+ {
+ code: 'async () => { return 4; }',
+ errors: [
+ {
+ message: 'Missing return type annotation.'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ excludeArrowFunctions: 'expressionsOnly'
+ }
+ ]
+ }
+ ],
+ valid: [
+ {
+ code: '(foo): string => {}'
+ },
+ {
+ code: '(foo): string => {}',
+ options: [
+ 'always'
+ ]
+ },
+ {
+ code: '(foo) => { return; }'
+ },
+ {
+ code: '(foo): Object => ( {} )'
+ },
+ {
+ code: '(foo) => { return undefined; }'
+ },
+ {
+ code: '(foo) => { return void 0; }'
+ },
+ {
+ code: '(foo): undefined => { return; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: '(foo): void => { return; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: '(foo) => { return; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'never'
+ }
+ ]
+ },
+ {
+ code: '(foo) => { return undefined; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'never'
+ }
+ ]
+ },
+ {
+ code: '(foo) => { return void 0; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'never'
+ }
+ ]
+ },
+ {
+ code: '(foo): undefined => { return undefined; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: '(foo): void => { return void 0; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: '(foo) => { return 1; }',
+ options: [
+ 'always'
+ ],
+ settings: {
+ flowtype: {
+ onlyFilesWithFlowAnnotation: true
+ }
+ }
+ },
+ {
+ code: '(foo) => { return undefined; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ],
+ settings: {
+ flowtype: {
+ onlyFilesWithFlowAnnotation: true
+ }
+ }
+ },
+ {
+ code: 'async function doThing(): Promise<void> {}',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: 'function* doThing(): Generator<number, void, void> { yield 2; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always'
+ }
+ ]
+ },
+ {
+ code: 'async (foo): Promise<number> => { return 3; }'
+ },
+ {
+ code: '() => 3',
+ options: [
+ 'always',
+ {
+ excludeArrowFunctions: true
+ }
+ ]
+ },
+ {
+ code: '() => { return 4; }',
+ options: [
+ 'always',
+ {
+ excludeArrowFunctions: true
+ }
+ ]
+ },
+ {
+ code: '() => undefined',
+ options: [
+ 'always',
+ {
+ excludeArrowFunctions: true
+ }
+ ]
+ },
+ {
+ code: '() => undefined',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always',
+ excludeArrowFunctions: true
+ }
+ ]
+ },
+ {
+ code: '() => { return undefined; }',
+ options: [
+ 'always',
+ {
+ annotateUndefined: 'always',
+ excludeArrowFunctions: true
+ }
+ ]
+ },
+ {
+ code: '() => 3',
+ options: [
+ 'always',
+ {
+ excludeArrowFunctions: 'expressionsOnly'
+ }
+ ]
+ },
+ {
+ code: 'async () => 3',
+ options: [
+ 'always',
+ {
+ excludeArrowFunctions: 'expressionsOnly'
+ }
+ ]
+ }
+ ]
+};
diff --git a/tests/rules/assertions/requireValidFileAnnotation.js b/tests/rules/assertions/requireValidFileAnnotation.js
new file mode 100644
index 0000000..a47ee38
--- /dev/null
+++ b/tests/rules/assertions/requireValidFileAnnotation.js
@@ -0,0 +1,146 @@
+export default {
+ invalid: [
+ {
+ code: ';// @flow',
+ errors: [
+ {
+ message: 'Flow file annotation not at the top of the file.'
+ }
+ ]
+ },
+ {
+ code: ';\n// @flow',
+ errors: [
+ {
+ message: 'Flow file annotation not at the top of the file.'
+ }
+ ]
+ },
+ {
+ code: '// @Flow',
+ errors: [
+ {
+ message: 'Malformed flow file annotation.'
+ }
+ ]
+ },
+ {
+ code: '// @floweeeeeee',
+ errors: [
+ {
+ message: 'Malformed flow file annotation.'
+ }
+ ]
+ },
+ {
+ code: '// @NoFlow',
+ errors: [
+ {
+ message: 'Malformed flow file annotation.'
+ }
+ ]
+ },
+ {
+ code: '// @nofloweeeeeee',
+ errors: [
+ {
+ message: 'Malformed flow file annotation.'
+ }
+ ]
+ },
+ {
+ code: 'a;',
+ errors: [
+ {
+ message: 'Flow file annotation is missing.'
+ }
+ ],
+ options: [
+ 'always'
+ ]
+ },
+ {
+ code: '/* @flow */',
+ errors: [
+ {
+ message: 'Flow file annotation style must be `// @flow`'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotationStyle: 'line'
+ }
+ ]
+ },
+ {
+ code: '// @flow',
+ errors: [
+ {
+ message: 'Flow file annotation style must be `/* @flow */`'
+ }
+ ],
+ options: [
+ 'always',
+ {
+ annotationStyle: 'block'
+ }
+ ]
+ }
+ ],
+ valid: [
+ {
+ code: 'a;'
+ },
+ {
+ code: '// @flow\na;'
+ },
+ {
+ code: '//@flow\na;'
+ },
+ {
+ code: '//**@flow\na;'
+ },
+ {
+ code: '/* foo @flow bar */\na;'
+ },
+ {
+ code: '\n\n// @flow\na;'
+ },
+ {
+ code: '// @flow\n// @FLow'
+ },
+ {
+ code: '// @noflow\na;'
+ },
+ {
+ code: 'a;',
+ options: ['always'],
+ settings: {
+ flowtype: {
+ onlyFilesWithFlowAnnotation: true
+ }
+ }
+ },
+ {
+ code: '// @flow',
+ options: [
+ 'always',
+ {
+ annotationStyle: 'line'
+ }
+ ]
+ },
+ {
+ code: '/* @flow */',
+ options: [
+ 'always',
+ {
+ annotationStyle: 'block'
+ }
+ ]
+ }
+ ]
+};
+
+
diff --git a/tests/rules/assertions/semi.js b/tests/rules/assertions/semi.js
new file mode 100644
index 0000000..cbb665d
--- /dev/null
+++ b/tests/rules/assertions/semi.js
@@ -0,0 +1,55 @@
+export default {
+ invalid: [
+ {
+ code: 'type FooType = {}',
+ errors: [
+ {
+ message: 'Missing semicolon.'
+ }
+ ],
+ options: [],
+ output: 'type FooType = {};'
+ },
+ {
+ code: 'type FooType = {}',
+ errors: [
+ {
+ message: 'Missing semicolon.'
+ }
+ ],
+ options: ['always'],
+ output: 'type FooType = {};'
+ },
+ {
+ code: 'type FooType = {};',
+ errors: [
+ {
+ message: 'Extra semicolon.'
+ }
+ ],
+ options: ['never'],
+ output: 'type FooType = {}'
+ }
+ ],
+ valid: [
+ {
+ code: 'type FooType = {};'
+ },
+ {
+ code: 'type FooType = {};',
+ options: ['always']
+ },
+ {
+ code: 'type FooType = { a: number;\n b: string;\n };',
+ options: ['always']
+ },
+ {
+ code: 'type FooType = { a: number;\n b: string;\n }',
+ options: ['never']
+ },
+ {
+ code: 'type FooType = {}',
+ options: ['never']
+ }
+ ]
+};
diff --git a/tests/rules/assertions/sortKeys.js b/tests/rules/assertions/sortKeys.js
new file mode 100644
index 0000000..b61754a
--- /dev/null
+++ b/tests/rules/assertions/sortKeys.js
@@ -0,0 +1,84 @@
+export default {
+ invalid: [
+ {
+ code: 'type FooType = { a: number, c: number, b: string }',
+ errors: [{message: 'Expected type annotations to be in ascending order. "b" should be before "c".'}]
+ },
+ {
+ code: 'type FooType = { a: number, b: number, C: number }',
+ errors: [{message: 'Expected type annotations to be in ascending order. "C" should be before "b".'}]
+ },
+ {
+ code: 'type FooType = { 1: number, 2: number, 10: number }',
+ errors: [{message: 'Expected type annotations to be in ascending order. "10" should be before "2".'}]
+ },
+ {
+ code: 'type FooType = { a: number, b: number }',
+ errors: [{message: 'Expected type annotations to be in descending order. "b" should be before "a".'}],
+ options: ['desc']
+ },
+ {
+ code: 'type FooType = { C: number, b: number, a: string }',
+ errors: [{message: 'Expected type annotations to be in descending order. "b" should be before "C".'}],
+ options: ['desc']
+ },
+ {
+ code: 'type FooType = { 10: number, 2: number, 1: number }',
+ errors: [{message: 'Expected type annotations to be in descending order. "2" should be before "10".'}],
+ options: ['desc']
+ },
+ {
+ code: 'type FooType = { a: number, c: number, C: number, b: string }',
+ errors: [{message: 'Expected type annotations to be in insensitive ascending order. "b" should be before "C".'}],
+ options: ['asc', {caseSensitive: false}]
+ },
+ {
+ code: 'type FooType = { a: number, C: number, c: number, b: string }',
+ errors: [{message: 'Expected type annotations to be in insensitive ascending order. "b" should be before "c".'}],
+ options: ['asc', {caseSensitive: false}]
+ },
+ {
+ code: 'type FooType = { 1: number, 10: number, 2: boolean }',
+ errors: [{message: 'Expected type annotations to be in natural ascending order. "2" should be before "10".'}],
+ options: ['asc', {natural: true}]
+ }
+ ],
+ valid: [
+ {
+ code: 'type FooType = { a: number }'
+ },
+ {
+ code: 'type FooType = { a: number, b: number, c: (boolean | number) }'
+ },
+ {
+ code: 'type FooType = { C: number, a: string, b: foo }'
+ },
+ {
+ code: 'type FooType = { 1: number, 10: number, 2: boolean }'
+ },
+ {
+ code: 'type FooType = { c: number, b: number, a: number }',
+ options: ['desc']
+ },
+ {
+ code: 'type FooType = { b: string, a: {}, C: number }',
+ options: ['desc']
+ },
+ {
+ code: 'type FooType = { 2: number, 10: number, 1: boolean }',
+ options: ['desc']
+ },
+ {
+ code: 'type FooType = { a: number, b: number, c: number, C: number }',
+ options: ['asc', {caseSensitive: false}]
+ },
+ {
+ code: 'type FooType = { a: number, b: number, C: number, c: number }',
+ options: ['asc', {caseSensitive: false}]
+ },
+ {
+ code: 'type FooType = { 1:number, 2: number, 10: number }',
+ options: ['asc', {natural: true}]
+ }
+ ]
+};
diff --git a/tests/rules/assertions/spaceAfterTypeColon.js b/tests/rules/assertions/spaceAfterTypeColon.js
new file mode 100644
index 0000000..6ddd35d
--- /dev/null
+++ b/tests/rules/assertions/spaceAfterTypeColon.js
@@ -0,0 +1,1014 @@
+import _ from 'lodash';
+
+const ARROW_FUNCTION_PARAMS = {
+ invalid: [
+ {
+ code: '(foo: string) => {}',
+ errors: [{message: 'There must be no space after "foo" parameter type annotation colon.'}],
+ options: ['never'],
+ output: '(foo:string) => {}'
+ },
+ {
+ code: '(foo: string) => {}',
+ errors: [{message: 'There must be 1 space after "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: '(foo: string) => {}'
+ },
+ {
+ code: '(foo:(() => void)) => {}',
+ errors: [{message: 'There must be a space after "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: '(foo: (() => void)) => {}'
+ },
+ {
+ code: '(foo: (() => void)) => {}',
+ errors: [{message: 'There must be no space after "foo" parameter type annotation colon.'}],
+ options: ['never'],
+ output: '(foo:(() => void)) => {}'
+ },
+ {
+ code: '(foo: (() => void)) => {}',
+ errors: [{message: 'There must be 1 space after "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: '(foo: (() => void)) => {}'
+ },
+ {
+ code: '({ lorem, ipsum, dolor } : SomeType) => {}',
+ errors: [{message: 'There must be 1 space after "{ lorem, ipsum, dolor }" parameter type annotation colon.'}],
+ output: '({ lorem, ipsum, dolor } : SomeType) => {}'
+ },
+ {
+ code: '(foo:{ a: string, b: number }) => {}',
+ errors: [{message: 'There must be a space after "foo" parameter type annotation colon.'}],
+ output: '(foo: { a: string, b: number }) => {}'
+ },
+ {
+ code: '({ a, b } :{ a: string, b: number }) => {}',
+ errors: [{message: 'There must be a space after "{ a, b }" parameter type annotation colon.'}],
+ output: '({ a, b } : { a: string, b: number }) => {}'
+ },
+ {
+ code: '([ a, b ] :string[]) => {}',
+ errors: [{message: 'There must be a space after "[ a, b ]" parameter type annotation colon.'}],
+ output: '([ a, b ] : string[]) => {}'
+ },
+ {
+ code: '(i?:number) => {}',
+ errors: [{message: 'There must be a space after "i" parameter type annotation colon.'}],
+ output: '(i?: number) => {}'
+ },
+ {
+ code: '(i?: number) => {}',
+ errors: [{message: 'There must be 1 space after "i" parameter type annotation colon.'}],
+ output: '(i?: number) => {}'
+ },
+ {
+ code: '(i?: number) => {}',
+ errors: [{message: 'There must be no space after "i" parameter type annotation colon.'}],
+ options: ['never'],
+ output: '(i?:number) => {}'
+ }
+ ],
+ valid: [
+ {
+ code: '(foo) => {}'
+ },
+ {
+ code: '(foo: string) => {}'
+ },
+ {
+ code: '(foo: (string|number)) => {}'
+ },
+ {
+ code: '(foo:string) => {}',
+ options: ['never']
+ },
+ {
+ code: '(foo: string) => {}',
+ options: ['always']
+ },
+ {
+ code: '(foo:(() => void)) => {}',
+ options: ['never']
+ },
+ {
+ code: '(foo: (() => void)) => {}',
+ options: ['always']
+ },
+ {
+ code: '({ lorem, ipsum, dolor }: SomeType) => {}'
+ },
+ {
+ code: '(foo: { a: string, b: number }) => {}'
+ },
+ {
+ code: '({ a, b }: ?{ a: string, b: number }) => {}'
+ },
+ {
+ code: '([ a, b ]: string[]) => {}'
+ },
+ {
+ code: '(i?: number) => {}'
+ },
+ {
+ code: '(i?:number) => {}',
+ options: ['never']
+ }
+ ]
+};
+
+const ARROW_FUNCTION_RETURN = {
+ invalid: [
+ {
+ code: '():Object => {}',
+ errors: [{message: 'There must be a space after return type colon.'}],
+ options: ['always'],
+ output: '(): Object => {}'
+ },
+ {
+ code: '(): Object => {}',
+ errors: [{message: 'There must be no space after return type colon.'}],
+ options: ['never'],
+ output: '():Object => {}'
+ },
+ {
+ code: '(): Object => {}',
+ errors: [{message: 'There must be 1 space after return type colon.'}],
+ options: ['always'],
+ output: '(): Object => {}'
+ },
+ {
+ code: '():(() => void) => {}',
+ errors: [{message: 'There must be a space after return type colon.'}],
+ options: ['always'],
+ output: '(): (() => void) => {}'
+ },
+ {
+ code: '(): (() => void) => {}',
+ errors: [{message: 'There must be no space after return type colon.'}],
+ options: ['never'],
+ output: '():(() => void) => {}'
+ },
+ {
+ code: '(): (() => void) => {}',
+ errors: [{message: 'There must be 1 space after return type colon.'}],
+ options: ['always'],
+ output: '(): (() => void) => {}'
+ }
+ ],
+ valid: [
+ {
+ code: '():Object => {}',
+ options: ['never']
+ },
+ {
+ code: '(): Object => {}',
+ options: ['always']
+ },
+ {
+ code: '():(number | string) => {}',
+ options: ['never']
+ },
+ {
+ code: '(): (number | string) => {}',
+ options: ['always']
+ },
+ {
+ code: '():number|string => {}',
+ options: ['never']
+ },
+ {
+ code: '(): number|string => {}',
+ options: ['always']
+ },
+ {
+ code: '():(() => void) => {}',
+ options: ['never']
+ },
+ {
+ code: '(): (() => void) => {}',
+ options: ['always']
+ },
+ {
+ code: '():( () => void ) => {}',
+ options: ['never']
+ },
+ {
+ code: '(): ( () => void ) => {}',
+ options: ['always']
+ },
+ {
+ code: '(): { a: number, b: string } => {}'
+ },
+ {
+ code: '() :{ a:number, b:string } => {}',
+ options: ['never']
+ }
+ ]
+};
+
+const FUNCTION_PARAMS = {
+ invalid: [
+ {
+ code: 'export default function (foo: string) {}',
+ errors: [{message: 'There must be no space after "foo" parameter type annotation colon.'}],
+ options: ['never'],
+ output: 'export default function (foo:string) {}'
+ },
+ {
+ code: 'function foo (foo: string) {}',
+ errors: [{message: 'There must be no space after "foo" parameter type annotation colon.'}],
+ options: ['never'],
+ output: 'function foo (foo:string) {}'
+ },
+ {
+ code: '(foo:string) => {}',
+ errors: [{message: 'There must be a space after "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: '(foo: string) => {}'
+ },
+ {
+ code: 'function foo (foo:string) {}',
+ errors: [{message: 'There must be a space after "foo" parameter type annotation colon.'}],
+ output: 'function foo (foo: string) {}'
+ },
+ {
+ code: 'async function foo({ lorem, ipsum, dolor }:SomeType) {}',
+ errors: [{message: 'There must be a space after "{ lorem, ipsum, dolor }" parameter type annotation colon.'}],
+ output: 'async function foo({ lorem, ipsum, dolor }: SomeType) {}'
+ },
+ {
+ code: 'function x(i?:number) {}',
+ errors: [{message: 'There must be a space after "i" parameter type annotation colon.'}],
+ output: 'function x(i?: number) {}'
+ },
+ {
+ code: 'function x(i?: number) {}',
+ errors: [{message: 'There must be 1 space after "i" parameter type annotation colon.'}],
+ output: 'function x(i?: number) {}'
+ },
+ {
+ code: 'function x(i?: number) {}',
+ errors: [{message: 'There must be no space after "i" parameter type annotation colon.'}],
+ options: ['never'],
+ output: 'function x(i?:number) {}'
+ }
+ ],
+ valid: [
+ {
+ code: 'function x(foo: string) {}'
+ },
+ {
+ code: 'class Foo { constructor(foo: string) {} }'
+ },
+ {
+ code: 'function x(foo:string) {}',
+ options: ['never']
+ },
+ {
+ code: 'class Foo { constructor(foo:string) {} }',
+ options: ['never']
+ },
+ {
+ code: 'async function foo({ lorem, ipsum, dolor }: SomeType) {}'
+ },
+ {
+ code: 'function x({ a, b }: { a: string, b: number }) {}'
+ },
+ {
+ code: 'function x(i?: number) {}'
+ },
+ {
+ code: 'function x(i?:number) {}',
+ options: ['never']
+ }
+ ]
+};
+
+const FUNCTION_RETURN = {
+ invalid: [
+ {
+ code: 'function a():x {}',
+ errors: [{message: 'There must be a space after return type colon.'}],
+ output: 'function a(): x {}'
+ },
+ {
+ code: 'function a(): x {}',
+ errors: [{message: 'There must be 1 space after return type colon.'}],
+ options: ['always'],
+ output: 'function a(): x {}'
+ },
+ {
+ code: 'function a(): x {}',
+ errors: [{message: 'There must be no space after return type colon.'}],
+ options: ['never'],
+ output: 'function a():x {}'
+ }
+ ],
+ valid: [
+ {
+ code: 'function a(): x {}'
+ },
+ {
+ code: 'function a():x {}',
+ options: ['never']
+ },
+ {
+ code: 'function a(): (number | string) {}'
+ },
+ {
+ code: 'function a() :(number | string) {}',
+ options: ['never']
+ }
+ ]
+};
+
+const FUNCTION_TYPE_PARAMS = {
+ invalid: [
+ {
+ code: 'type X = (foo:number) => string',
+ errors: [{message: 'There must be a space after "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo: number) => string'
+ },
+ {
+ code: 'type X = (foo: number) => string',
+ errors: [{message: 'There must be no space after "foo" parameter type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = (foo:number) => string'
+ },
+ {
+ code: 'type X = (foo: number) => string',
+ errors: [{message: 'There must be 1 space after "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo: number) => string'
+ },
+ {
+ code: 'type X = (foo:?number) => string',
+ errors: [{message: 'There must be a space after "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo: ?number) => string'
+ },
+ {
+ code: 'type X = (foo:(number)) => string',
+ errors: [{message: 'There must be a space after "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo: (number)) => string'
+ },
+ {
+ code: 'type X = (foo:((number))) => string',
+ errors: [{message: 'There must be a space after "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo: ((number))) => string'
+ },
+ {
+ code: 'type X = (foo: ((number))) => string',
+ errors: [{message: 'There must be 1 space after "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo: ((number))) => string'
+ },
+ {
+ code: 'type X = (foo: ((number))) => string',
+ errors: [{message: 'There must be no space after "foo" parameter type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = (foo:((number))) => string'
+ },
+ {
+ code: 'type X = (foo:?(number)) => string',
+ errors: [{message: 'There must be a space after "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo: ?(number)) => string'
+ },
+ {
+ code: 'type TArrayPredicate = (el: T, i?:number) => boolean',
+ errors: [{message: 'There must be a space after "i" parameter type annotation colon.'}],
+ output: 'type TArrayPredicate = (el: T, i?: number) => boolean'
+ },
+ {
+ code: 'type TArrayPredicate = (el: T, i?: number) => boolean',
+ errors: [{message: 'There must be 1 space after "i" parameter type annotation colon.'}],
+ output: 'type TArrayPredicate = (el: T, i?: number) => boolean'
+ },
+ {
+ code: 'type TArrayPredicate = (el:T, i?: number) => boolean',
+ errors: [{message: 'There must be no space after "i" parameter type annotation colon.'}],
+ options: ['never'],
+ output: 'type TArrayPredicate = (el:T, i?:number) => boolean'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = (foo: number) => string;'
+ },
+ {
+ code: 'type X = (foo : number) => string;'
+ },
+ {
+ code: 'type X = (foo: ?number) => string;'
+ },
+ {
+ code: 'type X = (foo? : ?number) => string;'
+ },
+ {
+ code: 'type X = (foo: ?{ x: number }) => string;'
+ },
+ {
+ code: 'type X = (foo:number) => string;',
+ options: ['never']
+ },
+ {
+ code: 'type X = (foo:?{ x:number }) => string;',
+ options: ['never']
+ },
+ {
+ code: 'type X = (foo: (number)) => string'
+ },
+ {
+ code: 'type X = (foo: ((number))) => string'
+ },
+ {
+ code: 'type X = (foo:((number))) => string',
+ options: ['never']
+ },
+ {
+ code: 'type X = ?(foo: ((number))) => string'
+ },
+ {
+ code: 'type X = ?(foo:((number))) => string',
+ options: ['never']
+ },
+ {
+ code: 'type TArrayPredicate = (el: T, i?: number) => boolean'
+ },
+ {
+ code: 'type TArrayPredicate = (el:T, i?:number) => boolean',
+ options: ['never']
+ }
+ ]
+};
+
+const CLASS_PROPERTIES = {
+ invalid: [
+ {
+ code: 'class X { foo:string }',
+ errors: [{message: 'There must be a space after "foo" class property type annotation colon.'}],
+ output: 'class X { foo: string }'
+ },
+ {
+ code: 'class X { foo: string }',
+ errors: [{message: 'There must be no space after "foo" class property type annotation colon.'}],
+ options: ['never'],
+ output: 'class X { foo:string }'
+ },
+ {
+ code: 'class X { foo:?string }',
+ errors: [{message: 'There must be a space after "foo" class property type annotation colon.'}],
+ output: 'class X { foo: ?string }'
+ },
+ {
+ code: 'class X { foo: ?string }',
+ errors: [{message: 'There must be no space after "foo" class property type annotation colon.'}],
+ options: ['never'],
+ output: 'class X { foo:?string }'
+ },
+ {
+ code: 'class X { static foo:number }',
+ errors: [{message: 'There must be a space after "foo" class property type annotation colon.'}],
+ output: 'class X { static foo: number }'
+ },
+ {
+ code: 'class X { static foo: number }',
+ errors: [{message: 'There must be no space after "foo" class property type annotation colon.'}],
+ options: ['never'],
+ output: 'class X { static foo:number }'
+ },
+ {
+ code: 'class X { static foo :number }',
+ errors: [{message: 'There must be a space after "foo" class property type annotation colon.'}],
+ output: 'class X { static foo : number }'
+ },
+ {
+ code: 'class X { static foo : number }',
+ errors: [{message: 'There must be no space after "foo" class property type annotation colon.'}],
+ options: ['never'],
+ output: 'class X { static foo :number }'
+ },
+ {
+ code: 'declare class X { static foo:number }',
+ errors: [{message: 'There must be a space after "foo" type annotation colon.'}],
+ output: 'declare class X { static foo: number }'
+ },
+ {
+ code: 'declare class X { static foo: number }',
+ errors: [{message: 'There must be no space after "foo" type annotation colon.'}],
+ options: ['never'],
+ output: 'declare class X { static foo:number }'
+ },
+ {
+ code: 'declare class X { static foo :number }',
+ errors: [{message: 'There must be a space after "foo" type annotation colon.'}],
+ output: 'declare class X { static foo : number }'
+ },
+ {
+ code: 'declare class X { static foo : number }',
+ errors: [{message: 'There must be no space after "foo" type annotation colon.'}],
+ options: ['never'],
+ output: 'declare class X { static foo :number }'
+ },
+ {
+ code: 'class X { +foo:string }',
+ errors: [{message: 'There must be a space after "foo" class property type annotation colon.'}],
+ output: 'class X { +foo: string }'
+ },
+ {
+ code: 'class X { +foo: string }',
+ errors: [{message: 'There must be 1 space after "foo" class property type annotation colon.'}],
+ output: 'class X { +foo: string }'
+ },
+ {
+ code: 'class X { +foo: string }',
+ errors: [{message: 'There must be no space after "foo" class property type annotation colon.'}],
+ options: ['never'],
+ output: 'class X { +foo:string }'
+ },
+ {
+ code: 'class X { static +foo:string }',
+ errors: [{message: 'There must be a space after "foo" class property type annotation colon.'}],
+ output: 'class X { static +foo: string }'
+ },
+ {
+ code: 'class X { static +foo: string }',
+ errors: [{message: 'There must be 1 space after "foo" class property type annotation colon.'}],
+ output: 'class X { static +foo: string }'
+ },
+ {
+ code: 'class X { static +foo: string }',
+ errors: [{message: 'There must be no space after "foo" class property type annotation colon.'}],
+ options: ['never'],
+ output: 'class X { static +foo:string }'
+ }
+ ],
+ valid: [
+ {
+ code: 'class Foo { bar }'
+ },
+ {
+ code: 'class Foo { bar = 3 }'
+ },
+ {
+ code: 'class Foo { bar: string }'
+ },
+ {
+ code: 'class Foo { bar: ?string }'
+ },
+ {
+ code: 'class Foo { bar:string }',
+ options: ['never']
+ },
+ {
+ code: 'class Foo { bar:?string }',
+ options: ['never']
+ },
+ {
+ code: 'class X { static foo : number }'
+ },
+ {
+ code: 'class X { static foo :number }',
+ options: ['never']
+ },
+ {
+ code: 'declare class X { static foo : number }'
+ },
+ {
+ code: 'declare class X { static foo :number }',
+ options: ['never']
+ },
+ {
+ code: 'class X { +foo: string }'
+ },
+ {
+ code: 'class X { static +foo: string }'
+ },
+ {
+ code: 'class X { +foo:string }',
+ options: ['never']
+ },
+ {
+ code: 'class X { static +foo:string }',
+ options: ['never']
+ }
+ ]
+};
+
+const OBJECT_TYPE_PROPERTIES = {
+ invalid: [
+ {
+ code: 'type X = { foo:string }',
+ errors: [{message: 'There must be a space after "foo" type annotation colon.'}],
+ output: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo:string }',
+ errors: [{message: 'There must be a space after "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo: string }',
+ errors: [{message: 'There must be no space after "foo" type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { foo:string }'
+ },
+ {
+ code: 'type X = { foo: string }',
+ errors: [{message: 'There must be 1 space after "foo" type annotation colon.'}],
+ output: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo?:string }',
+ errors: [{message: 'There must be a space after "foo" type annotation colon.'}],
+ output: 'type X = { foo?: string }'
+ },
+ {
+ code: 'type X = { foo?: string }',
+ errors: [{message: 'There must be no space after "foo" type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { foo?:string }'
+ },
+ {
+ code: 'type X = { foo?:?string }',
+ errors: [{message: 'There must be a space after "foo" type annotation colon.'}],
+ output: 'type X = { foo?: ?string }'
+ },
+ {
+ code: 'type X = { foo?: ?string }',
+ errors: [{message: 'There must be 1 space after "foo" type annotation colon.'}],
+ output: 'type X = { foo?: ?string }'
+ },
+ {
+ code: 'type Foo = { barType:(string | () => void) }',
+ errors: [{message: 'There must be a space after "barType" type annotation colon.'}],
+ output: 'type Foo = { barType: (string | () => void) }'
+ },
+ {
+ code: 'type Foo = { barType:(((string | () => void))) }',
+ errors: [{message: 'There must be a space after "barType" type annotation colon.'}],
+ output: 'type Foo = { barType: (((string | () => void))) }'
+ },
+ {
+ code: 'type Foo = { barType: (string | () => void) }',
+ errors: [{message: 'There must be no space after "barType" type annotation colon.'}],
+ options: ['never'],
+ output: 'type Foo = { barType:(string | () => void) }'
+ },
+ {
+ code: 'type Foo = { barType: (string | () => void) }',
+ errors: [{message: 'There must be 1 space after "barType" type annotation colon.'}],
+ output: 'type Foo = { barType: (string | () => void) }'
+ },
+ {
+ code: 'type Foo = { barType: ((string | () => void)) }',
+ errors: [{message: 'There must be 1 space after "barType" type annotation colon.'}],
+ output: 'type Foo = { barType: ((string | () => void)) }'
+ },
+ {
+ code: 'type X = { get:() => A; }',
+ errors: [{message: 'There must be a space after "get" type annotation colon.'}],
+ output: 'type X = { get: () => A; }'
+ },
+ {
+ code: 'type X = { get:<X>() => A; }',
+ errors: [{message: 'There must be a space after "get" type annotation colon.'}],
+ output: 'type X = { get: <X>() => A; }'
+ },
+ {
+ code: 'type X = { get: () => A; }',
+ errors: [{message: 'There must be no space after "get" type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { get:() => A; }'
+ },
+ {
+ code: 'type X = { get: <X>() => A; }',
+ errors: [{message: 'There must be no space after "get" type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { get:<X>() => A; }'
+ },
+ {
+ code: 'type X = { get: () => A; }',
+ errors: [{message: 'There must be 1 space after "get" type annotation colon.'}],
+ output: 'type X = { get: () => A; }'
+ },
+ {
+ code: 'type X = { get: <X>() => A; }',
+ errors: [{message: 'There must be 1 space after "get" type annotation colon.'}],
+ output: 'type X = { get: <X>() => A; }'
+ },
+ {
+ code: 'type X = { +foo:string }',
+ errors: [{message: 'There must be a space after "foo" type annotation colon.'}],
+ output: 'type X = { +foo: string }'
+ },
+ {
+ code: 'type X = { +foo: string }',
+ errors: [{message: 'There must be 1 space after "foo" type annotation colon.'}],
+ output: 'type X = { +foo: string }'
+ },
+ {
+ code: 'type X = { +foo: string }',
+ errors: [{message: 'There must be no space after "foo" type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { +foo:string }'
+ },
+ {
+ code: 'type X = { +foo?:string }',
+ errors: [{message: 'There must be a space after "foo" type annotation colon.'}],
+ output: 'type X = { +foo?: string }'
+ },
+ {
+ code: 'type X = { +foo?: string }',
+ errors: [{message: 'There must be 1 space after "foo" type annotation colon.'}],
+ output: 'type X = { +foo?: string }'
+ },
+ {
+ code: 'type X = { +foo?: string }',
+ errors: [{message: 'There must be no space after "foo" type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { +foo?:string }'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo:string }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { foo?: string }'
+ },
+ {
+ code: 'type X = { foo?: ?string }'
+ },
+ {
+ code: 'type X = { foo?:?string }',
+ options: ['never']
+ },
+ {
+ code: 'type Foo = { barType: (string | () => void) }'
+ },
+ {
+ code: 'type Foo = { barType: ((string | () => void)) }'
+ },
+ {
+ code: 'type Foo = { barType:(string | () => void) }',
+ options: ['never']
+ },
+ {
+ code: 'type Foo = { barType:((string | () => void)) }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { get(): A; }'
+ },
+ {
+ code: 'type X = { get<X>(): A; }'
+ },
+ {
+ code: 'type X = { get(): A; }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { get<X>(): A; }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { get: () => A; }'
+ },
+ {
+ code: 'type X = { get: <X>() => A; }'
+ },
+ {
+ code: 'type X = { get:() => A; }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { get:<X>() => A; }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { +foo: string }'
+ },
+ {
+ code: 'type X = { +foo?: string }'
+ },
+ {
+ code: 'type X = { +foo:string }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { +foo?:string }',
+ options: ['never']
+ }
+ ]
+};
+
+
+const OBJECT_TYPE_INDEXERS = {
+ invalid: [
+ // [id:key]: value
+ // ^
+ {
+ code: 'type X = { [a:b]: c }',
+ errors: [{message: 'There must be a space after type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { [a: b]: c }'
+ },
+ {
+ code: 'type X = { [a: b]:c }',
+ errors: [{message: 'There must be no space after type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { [a:b]:c }'
+ },
+ {
+ code: 'type X = { [a: b]: c }',
+ errors: [{message: 'There must be 1 space after type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { [a: b]: c }'
+ },
+ {
+ code: 'type X = { +[a:b]: c }',
+ errors: [{message: 'There must be a space after type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { +[a: b]: c }'
+ },
+ {
+ code: 'type X = { +[a: b]:c }',
+ errors: [{message: 'There must be no space after type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { +[a:b]:c }'
+ },
+ {
+ code: 'type X = { +[a: b]: c }',
+ errors: [{message: 'There must be 1 space after type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { +[a: b]: c }'
+ },
+ // [id:key]: value
+ // ^
+ {
+ code: 'type X = { [a: b]:c }',
+ errors: [{message: 'There must be a space after type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { [a: b]: c }'
+ },
+ {
+ code: 'type X = { [a:b]: c }',
+ errors: [{message: 'There must be no space after type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { [a:b]:c }'
+ },
+ {
+ code: 'type X = { [a: b]: c }',
+ errors: [{message: 'There must be 1 space after type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { [a: b]: c }'
+ },
+ // [id:key]: value
+ // ^ ^
+ {
+ code: 'type X = { [a:b]:c }',
+ errors: [
+ {message: 'There must be a space after type annotation colon.'},
+ {message: 'There must be a space after type annotation colon.'}
+ ],
+ options: ['always'],
+ output: 'type X = { [a: b]: c }'
+ },
+ {
+ code: 'type X = { [a: b]: c }',
+ errors: [
+ {message: 'There must be no space after type annotation colon.'},
+ {message: 'There must be no space after type annotation colon.'}
+ ],
+ options: ['never'],
+ output: 'type X = { [a:b]:c }'
+ },
+ {
+ code: 'type X = { [a: b]: c }',
+ errors: [
+ {message: 'There must be 1 space after type annotation colon.'},
+ {message: 'There must be 1 space after type annotation colon.'}
+ ],
+ options: ['always'],
+ output: 'type X = { [a: b]: c }'
+ },
+ {
+ code: 'type X = { [a:(b)]:(c) }',
+ errors: [
+ {message: 'There must be a space after type annotation colon.'},
+ {message: 'There must be a space after type annotation colon.'}
+ ],
+ options: ['always'],
+ output: 'type X = { [a: (b)]: (c) }'
+ },
+ {
+ code: 'type X = { [a: (b)]: (c) }',
+ errors: [
+ {message: 'There must be no space after type annotation colon.'},
+ {message: 'There must be no space after type annotation colon.'}
+ ],
+ options: ['never'],
+ output: 'type X = { [a:(b)]:(c) }'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = { [a: b]: c }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { [a:b]:c }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { +[a: b]: c }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { +[a:b]:c }',
+ options: ['never']
+ }
+ ]
+};
+
+
+const TYPE_CAST_EXPRESSIONS = {
+ invalid: [
+ {
+ code: 'const x = ({}: {})',
+ errors: [{message: 'There must be no space after type cast colon.'}],
+ options: ['never'],
+ output: 'const x = ({}:{})'
+ },
+ {
+ code: 'const x = ({}:{})',
+ errors: [{message: 'There must be a space after type cast colon.'}],
+ options: ['always'],
+ output: 'const x = ({}: {})'
+ },
+ {
+ code: 'const x = ({}: {})',
+ errors: [{message: 'There must be 1 space after type cast colon.'}],
+ options: ['always'],
+ output: 'const x = ({}: {})'
+ },
+ {
+ code: '((x): (string))',
+ errors: [{message: 'There must be no space after type cast colon.'}],
+ options: ['never'],
+ output: '((x):(string))'
+ },
+ {
+ code: '((x):(string))',
+ errors: [{message: 'There must be a space after type cast colon.'}],
+ options: ['always'],
+ output: '((x): (string))'
+ },
+ {
+ code: '((x): (string))',
+ errors: [{message: 'There must be 1 space after type cast colon.'}],
+ options: ['always'],
+ output: '((x): (string))'
+ }
+ ],
+ valid: [
+ {
+ code: 'const x = ({}:{})',
+ options: ['never']
+ },
+ {
+ code: 'const x = ({}: {})',
+ options: ['always']
+ },
+ {
+ code: '((x):(string))',
+ options: ['never']
+ },
+ {
+ code: '((x): (string))',
+ options: ['always']
+ }
+ ]
+};
+
+
+const ALL = [
+ ARROW_FUNCTION_PARAMS,
+ ARROW_FUNCTION_RETURN,
+ FUNCTION_PARAMS,
+ FUNCTION_RETURN,
+ FUNCTION_TYPE_PARAMS,
+ CLASS_PROPERTIES,
+ OBJECT_TYPE_PROPERTIES,
+ OBJECT_TYPE_INDEXERS,
+ TYPE_CAST_EXPRESSIONS
+];
+
+export default {
+ invalid: _.flatMap(ALL, (rules) => { return rules.invalid; }),
+ valid: _.flatMap(ALL, (rules) => { return rules.valid; })
+};
diff --git a/tests/rules/assertions/spaceBeforeGenericBracket.js b/tests/rules/assertions/spaceBeforeGenericBracket.js
new file mode 100644
index 0000000..d25bbf2
--- /dev/null
+++ b/tests/rules/assertions/spaceBeforeGenericBracket.js
@@ -0,0 +1,41 @@
+export default {
+ invalid: [
+ {
+ code: 'type X = Promise <string>',
+ errors: [{message: 'There must be no space before "Promise" generic type annotation bracket'}],
+ output: 'type X = Promise<string>'
+ },
+ {
+ code: 'type X = Promise <string>',
+ errors: [{message: 'There must be no space before "Promise" generic type annotation bracket'}],
+ options: ['never'],
+ output: 'type X = Promise<string>'
+ },
+ {
+ code: 'type X = Promise <string>',
+ errors: [{message: 'There must be no space before "Promise" generic type annotation bracket'}],
+ output: 'type X = Promise<string>'
+ },
+ {
+ code: 'type X = Promise<string>',
+ errors: [{message: 'There must be a space before "Promise" generic type annotation bracket'}],
+ options: ['always'],
+ output: 'type X = Promise <string>'
+ },
+ {
+ code: 'type X = Promise <string>',
+ errors: [{message: 'There must be one space before "Promise" generic type annotation bracket'}],
+ options: ['always'],
+ output: 'type X = Promise <string>'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = Promise<string>'
+ },
+ {
+ code: 'type X = Promise <string>',
+ options: ['always']
+ }
+ ]
+};
diff --git a/tests/rules/assertions/spaceBeforeTypeColon.js b/tests/rules/assertions/spaceBeforeTypeColon.js
new file mode 100644
index 0000000..aa1fe02
--- /dev/null
+++ b/tests/rules/assertions/spaceBeforeTypeColon.js
@@ -0,0 +1,845 @@
+import _ from 'lodash';
+
+const ARROW_FUNCTION_PARAMS = {
+ invalid: [
+ {
+ code: '(foo : string) => {}',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ options: ['never'],
+ output: '(foo: string) => {}'
+ },
+ {
+ code: '(foo ? : string) => {}',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ options: ['never'],
+ output: '(foo ?: string) => {}'
+ },
+ {
+ code: '(foo: string) => {}',
+ errors: [{message: 'There must be a space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: '(foo : string) => {}'
+ },
+ {
+ code: '(foo : string) => {}',
+ errors: [{message: 'There must be 1 space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: '(foo : string) => {}'
+ },
+ {
+ code: '(foo?: string) => {}',
+ errors: [{message: 'There must be a space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: '(foo? : string) => {}'
+ },
+ {
+ code: '(foo ? : string) => {}',
+ errors: [{message: 'There must be 1 space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: '(foo ? : string) => {}'
+ },
+ {
+ code: '(foo ?: string) => {}',
+ errors: [{message: 'There must be a space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: '(foo ? : string) => {}'
+ },
+ {
+ code: '({ lorem, ipsum, dolor } : SomeType) => {}',
+ errors: [{message: 'There must be no space before "{ lorem, ipsum, dolor }" parameter type annotation colon.'}],
+ output: '({ lorem, ipsum, dolor }: SomeType) => {}'
+ },
+ {
+ code: '(foo : { a: string, b: number }) => {}',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ output: '(foo: { a: string, b: number }) => {}'
+ },
+ {
+ code: '({ a, b } : { a: string, b: number }) => {}',
+ errors: [{message: 'There must be no space before "{ a, b }" parameter type annotation colon.'}],
+ output: '({ a, b }: { a: string, b: number }) => {}'
+ },
+ {
+ code: '([ a, b ] : string[]) => {}',
+ errors: [{message: 'There must be no space before "[ a, b ]" parameter type annotation colon.'}],
+ output: '([ a, b ]: string[]) => {}'
+ }
+ ],
+ valid: [
+ {
+ code: '(foo) => {}'
+ },
+ {
+ code: '(foo: string) => {}'
+ },
+ {
+ code: '(foo?: string) => {}'
+ },
+ {
+ code: '(foo ?: string) => {}'
+ },
+ {
+ code: '(foo: string) => {}',
+ options: ['never']
+ },
+ {
+ code: '(foo : string) => {}',
+ options: ['always']
+ },
+ {
+ code: '(foo? : string) => {}',
+ options: ['always']
+ },
+ {
+ code: '(foo ? : string) => {}',
+ options: ['always']
+ },
+ {
+ code: '(foo ? : string) => {}',
+ options: ['always']
+ },
+ {
+ code: '({ lorem, ipsum, dolor }: SomeType) => {}'
+ },
+ {
+ code: '(foo: { a: string, b: number }) => {}'
+ },
+ {
+ code: '({ a, b }: ?{ a: string, b: number }) => {}'
+ },
+ {
+ code: '(): { a: number, b: string } => {}'
+ },
+ {
+ code: '() : { a : number, b : string } => {}',
+ options: ['always']
+ },
+ {
+ code: '([ a, b ]: string[]) => {}'
+ }
+ ]
+};
+
+const ARROW_FUNCTION_RETURN = {
+ invalid: [
+ {
+ code: '() : x => {}',
+ errors: [{message: 'There must be no space before return type colon.'}],
+ output: '(): x => {}'
+ },
+ {
+ code: '(): x => {}',
+ errors: [{message: 'There must be a space before return type colon.'}],
+ options: ['always'],
+ output: '() : x => {}'
+ },
+ {
+ code: '() : x => {}',
+ errors: [{message: 'There must be 1 space before return type colon.'}],
+ options: ['always'],
+ output: '() : x => {}'
+ }
+ ],
+ valid: [
+ {
+ code: '(): x => {}'
+ },
+ {
+ code: '() : x => {}',
+ options: ['always']
+ },
+ {
+ code: '(): (number | string) => {}'
+ },
+ {
+ code: '() : (number | string) => {}',
+ options: ['always']
+ }
+ ]
+};
+
+const FUNCTION_PARAMS = {
+ invalid: [
+ {
+ code: 'function x(foo : string) {}',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ output: 'function x(foo: string) {}'
+ },
+ {
+ code: 'function x(foo: string) {}',
+ errors: [{message: 'There must be a space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: 'function x(foo : string) {}'
+ },
+ {
+ code: 'var x = function (foo : string) {}',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ output: 'var x = function (foo: string) {}'
+ },
+ {
+ code: 'var x = function (foo: string) {}',
+ errors: [{message: 'There must be a space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: 'var x = function (foo : string) {}'
+ },
+ {
+ code: 'class Foo { constructor(foo : string ) {} }',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ output: 'class Foo { constructor(foo: string ) {} }'
+ },
+ {
+ code: 'class Foo { constructor(foo: string ) {} }',
+ errors: [{message: 'There must be a space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: 'class Foo { constructor(foo : string ) {} }'
+ },
+ {
+ code: 'async function foo({ lorem, ipsum, dolor } : SomeType) {}',
+ errors: [{message: 'There must be no space before "{ lorem, ipsum, dolor }" parameter type annotation colon.'}],
+ output: 'async function foo({ lorem, ipsum, dolor }: SomeType) {}'
+ }
+ ],
+ valid: [
+ {
+ code: 'function x(foo: string) {}'
+ },
+ {
+ code: 'function x(foo : string) {}',
+ options: ['always']
+ },
+ {
+ code: 'var x = function (foo: string) {}'
+ },
+ {
+ code: 'var x = function (foo : string) {}',
+ options: ['always']
+ },
+ {
+ code: 'class X { foo({ bar }: Props = this.props) {} }'
+ },
+ {
+ code: 'class Foo { constructor(foo: string ) {} }'
+ },
+ {
+ code: 'class Foo { constructor(foo : string ) {} }',
+ options: ['always']
+ },
+ {
+ code: 'async function foo({ lorem, ipsum, dolor }: SomeType) {}'
+ },
+ {
+ code: 'function x({ a, b }: { a: string, b: number }) {}'
+ }
+ ]
+};
+
+const FUNCTION_RETURN = {
+ invalid: [
+ {
+ code: 'function a() : x {}',
+ errors: [{message: 'There must be no space before return type colon.'}],
+ output: 'function a(): x {}'
+ },
+ {
+ code: 'function a(): x {}',
+ errors: [{message: 'There must be a space before return type colon.'}],
+ options: ['always'],
+ output: 'function a() : x {}'
+ },
+ {
+ code: 'function a() : x {}',
+ errors: [{message: 'There must be 1 space before return type colon.'}],
+ options: ['always'],
+ output: 'function a() : x {}'
+ }
+ ],
+ valid: [
+ {
+ code: 'function a(): x {}'
+ },
+ {
+ code: 'function a() : x {}',
+ options: ['always']
+ },
+ {
+ code: 'function a(): (number | string) {}'
+ },
+ {
+ code: 'function a() : (number | string) {}',
+ options: ['always']
+ }
+ ]
+};
+
+const FUNCTION_TYPE_PARAMS = {
+ invalid: [
+ {
+ code: 'type X = (foo :string) => string;',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo:string) => string;'
+ },
+ {
+ code: 'type X = (foo:string) => string;',
+ errors: [{message: 'There must be a space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = (foo :string) => string;'
+ },
+ {
+ code: 'type X = (foo :string) => string;',
+ errors: [{message: 'There must be 1 space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = (foo :string) => string;'
+ },
+ {
+ code: 'type X = (foo? :string) => string;',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo?:string) => string;'
+ },
+ {
+ code: 'type X = (foo? :string) => string;',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo?:string) => string;'
+ },
+ {
+ code: 'type X = (foo?:string) => string;',
+ errors: [{message: 'There must be a space before "foo" parameter type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = (foo? :string) => string;'
+ },
+ {
+ code: 'type X = (foo? :?string) => string;',
+ errors: [{message: 'There must be no space before "foo" parameter type annotation colon.'}],
+ output: 'type X = (foo?:?string) => string;'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = (foo:string) => number;'
+ },
+ {
+ code: 'type X = (foo: string) => number;'
+ },
+ {
+ code: 'type X = (foo: ?string) => number;'
+ },
+ {
+ code: 'type X = (foo?: string) => number;'
+ },
+ {
+ code: 'type X = (foo?: ?string) => number;'
+ },
+ {
+ code: 'type X = (foo ?: string) => number;'
+ },
+ {
+ code: 'type X = (foo? : string) => number',
+ options: ['always']
+ },
+ {
+ code: 'type X = (foo? : ?string) => number',
+ options: ['always']
+ }
+ ]
+};
+
+const CLASS_PROPERTIES = {
+ invalid: [
+ {
+ code: 'class X { foo :string }',
+ errors: [{message: 'There must be no space before "foo" class property type annotation colon.'}],
+ output: 'class X { foo:string }'
+ },
+ {
+ code: 'class X { foo: string }',
+ errors: [{message: 'There must be a space before "foo" class property type annotation colon.'}],
+ options: ['always'],
+ output: 'class X { foo : string }'
+ },
+ {
+ code: 'class X { foo :?string }',
+ errors: [{message: 'There must be no space before "foo" class property type annotation colon.'}],
+ output: 'class X { foo:?string }'
+ },
+ {
+ code: 'class X { foo: ?string }',
+ errors: [{message: 'There must be a space before "foo" class property type annotation colon.'}],
+ options: ['always'],
+ output: 'class X { foo : ?string }'
+ },
+ {
+ code: 'class X { static foo : number }',
+ errors: [{message: 'There must be no space before "foo" class property type annotation colon.'}],
+ output: 'class X { static foo: number }'
+ },
+ {
+ code: 'class X { static foo :number }',
+ errors: [{message: 'There must be no space before "foo" class property type annotation colon.'}],
+ output: 'class X { static foo:number }'
+ },
+ {
+ code: 'class X { static foo: number }',
+ errors: [{message: 'There must be a space before "foo" class property type annotation colon.'}],
+ options: ['always'],
+ output: 'class X { static foo : number }'
+ },
+ {
+ code: 'class X { static foo:number }',
+ errors: [{message: 'There must be a space before "foo" class property type annotation colon.'}],
+ options: ['always'],
+ output: 'class X { static foo :number }'
+ },
+ {
+ code: 'declare class Foo { static bar :number; }',
+ errors: [{message: 'There must be no space before "bar" type annotation colon.'}],
+ output: 'declare class Foo { static bar:number; }'
+ },
+ {
+ code: 'declare class Foo { static bar : number; }',
+ errors: [{message: 'There must be no space before "bar" type annotation colon.'}],
+ output: 'declare class Foo { static bar: number; }'
+ },
+ {
+ code: 'declare class Foo { static bar:number; }',
+ errors: [{message: 'There must be a space before "bar" type annotation colon.'}],
+ options: ['always'],
+ output: 'declare class Foo { static bar :number; }'
+ },
+ {
+ code: 'declare class Foo { static bar: number; }',
+ errors: [{message: 'There must be a space before "bar" type annotation colon.'}],
+ options: ['always'],
+ output: 'declare class Foo { static bar : number; }'
+ },
+ {
+ code: 'class X { +foo: string }',
+ errors: [{message: 'There must be a space before "foo" class property type annotation colon.'}],
+ options: ['always'],
+ output: 'class X { +foo : string }'
+ },
+ {
+ code: 'class X { +foo : string }',
+ errors: [{message: 'There must be 1 space before "foo" class property type annotation colon.'}],
+ options: ['always'],
+ output: 'class X { +foo : string }'
+ },
+ {
+ code: 'class X { +foo : string }',
+ errors: [{message: 'There must be no space before "foo" class property type annotation colon.'}],
+ options: ['never'],
+ output: 'class X { +foo: string }'
+ },
+ {
+ code: 'class X { static +foo: string }',
+ errors: [{message: 'There must be a space before "foo" class property type annotation colon.'}],
+ options: ['always'],
+ output: 'class X { static +foo : string }'
+ },
+ {
+ code: 'class X { static +foo : string }',
+ errors: [{message: 'There must be 1 space before "foo" class property type annotation colon.'}],
+ options: ['always'],
+ output: 'class X { static +foo : string }'
+ },
+ {
+ code: 'class X { static +foo : string }',
+ errors: [{message: 'There must be no space before "foo" class property type annotation colon.'}],
+ options: ['never'],
+ output: 'class X { static +foo: string }'
+ }
+ ],
+ valid: [
+ {
+ code: 'class Foo { bar }'
+ },
+ {
+ code: 'class Foo { bar = 3 }'
+ },
+ {
+ code: 'class Foo { bar: string }'
+ },
+ {
+ code: 'class Foo { bar: ?string }'
+ },
+ {
+ code: 'class Foo { bar:?string }'
+ },
+ {
+ code: 'class Foo { bar : string }',
+ options: ['always']
+ },
+ {
+ code: 'class X { static foo:number }'
+ },
+ {
+ code: 'class X { static foo: number }'
+ },
+ {
+ code: 'class X { static foo :number }',
+ options: ['always']
+ },
+ {
+ code: 'class X { static foo : number }',
+ options: ['always']
+ },
+ {
+ code: 'declare class Foo { static bar:number; }'
+ },
+ {
+ code: 'declare class Foo { static bar :number; }',
+ options: ['always']
+ },
+ {
+ code: 'declare class Foo { static bar: number; }'
+ },
+ {
+ code: 'declare class Foo { static bar : number; }',
+ options: ['always']
+ },
+ {
+ code: 'class X { +foo: string }'
+ },
+ {
+ code: 'class X { static +foo: string }'
+ },
+ {
+ code: 'class X { +foo : string }',
+ options: ['always']
+ },
+ {
+ code: 'class X { static +foo : string }',
+ options: ['always']
+ }
+ ]
+};
+
+const OBJECT_TYPE_PROPERTIES = {
+ invalid: [
+ {
+ code: 'type X = { foo : string }',
+ errors: [{message: 'There must be no space before "foo" type annotation colon.'}],
+ output: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo : string }',
+ errors: [{message: 'There must be no space before "foo" type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo: string }',
+ errors: [{message: 'There must be a space before "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { foo : string }'
+ },
+ {
+ code: 'type X = { foo : string }',
+ errors: [{message: 'There must be 1 space before "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { foo : string }'
+ },
+ {
+ code: 'type X = { foo? : string }',
+ errors: [{message: 'There must be no space before "foo" type annotation colon.'}],
+ output: 'type X = { foo?: string }'
+ },
+ {
+ code: 'type X = { foo?: string }',
+ errors: [{message: 'There must be a space before "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { foo? : string }'
+ },
+ {
+ code: 'type X = { foo? : string }',
+ errors: [{message: 'There must be 1 space before "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { foo? : string }'
+ },
+ {
+ code: 'type X = { foo ?: string }',
+ errors: [{message: 'There must be a space before "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { foo ? : string }'
+ },
+ {
+ code: 'type X = { +foo: string }',
+ errors: [{message: 'There must be a space before "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { +foo : string }'
+ },
+ {
+ code: 'type X = { +foo : string }',
+ errors: [{message: 'There must be 1 space before "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { +foo : string }'
+ },
+ {
+ code: 'type X = { +foo : string }',
+ errors: [{message: 'There must be no space before "foo" type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { +foo: string }'
+ },
+ {
+ code: 'type X = { +foo?: string }',
+ errors: [{message: 'There must be a space before "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { +foo? : string }'
+ },
+ {
+ code: 'type X = { +foo? : string }',
+ errors: [{message: 'There must be 1 space before "foo" type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { +foo? : string }'
+ },
+ {
+ code: 'type X = { +foo? : string }',
+ errors: [{message: 'There must be no space before "foo" type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { +foo?: string }'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = { foo: string }'
+ },
+ {
+ code: 'type X = { foo : string }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { foo?: string }'
+ },
+ {
+ code: 'type X = { foo ?: string }'
+ },
+ {
+ code: 'type X = { foo? : string }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { +foo: string }'
+ },
+ {
+ code: 'type X = { +foo?: string }'
+ },
+ {
+ code: 'type X = { +foo : string }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { +foo? : string }',
+ options: ['always']
+ }
+ ]
+};
+
+const OBJECT_TYPE_INDEXERS = {
+ invalid: [
+ // [id:key]: value
+ // ^
+ {
+ code: 'type X = { [a: b] : c }',
+ errors: [{message: 'There must be a space before type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { [a : b] : c }'
+ },
+ {
+ code: 'type X = { [a : b]: c }',
+ errors: [{message: 'There must be no space before type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { [a: b]: c }'
+ },
+ {
+ code: 'type X = { [a : b] : c }',
+ errors: [{message: 'There must be 1 space before type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { [a : b] : c }'
+ },
+ {
+ code: 'type X = { +[a:b] : c }',
+ errors: [{message: 'There must be a space before type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { +[a :b] : c }'
+ },
+ {
+ code: 'type X = { +[a : b]: c }',
+ errors: [{message: 'There must be no space before type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { +[a: b]: c }'
+ },
+ {
+ code: 'type X = { +[a : b] : c }',
+ errors: [{message: 'There must be 1 space before type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { +[a : b] : c }'
+ },
+ // [id:key]: value
+ // ^
+ {
+ code: 'type X = { [a : b]: c }',
+ errors: [{message: 'There must be a space before type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { [a : b] : c }'
+ },
+ {
+ code: 'type X = { [a: b] : c }',
+ errors: [{message: 'There must be no space before type annotation colon.'}],
+ options: ['never'],
+ output: 'type X = { [a: b]: c }'
+ },
+ {
+ code: 'type X = { [a : b] : c }',
+ errors: [{message: 'There must be 1 space before type annotation colon.'}],
+ options: ['always'],
+ output: 'type X = { [a : b] : c }'
+ },
+ // [id:key]: value
+ // ^ ^
+ {
+ code: 'type X = { [a:b]:c }',
+ errors: [
+ {message: 'There must be a space before type annotation colon.'},
+ {message: 'There must be a space before type annotation colon.'}
+ ],
+ options: ['always'],
+ output: 'type X = { [a :b] :c }'
+ },
+ {
+ code: 'type X = { [a : b] : c }',
+ errors: [
+ {message: 'There must be no space before type annotation colon.'},
+ {message: 'There must be no space before type annotation colon.'}
+ ],
+ options: ['never'],
+ output: 'type X = { [a: b]: c }'
+ },
+ {
+ code: 'type X = { [a : b] : c }',
+ errors: [
+ {message: 'There must be 1 space before type annotation colon.'},
+ {message: 'There must be 1 space before type annotation colon.'}
+ ],
+ options: ['always'],
+ output: 'type X = { [a : b] : c }'
+ },
+ {
+ code: 'type X = { [a:(b)]:(c) }',
+ errors: [
+ {message: 'There must be a space before type annotation colon.'},
+ {message: 'There must be a space before type annotation colon.'}
+ ],
+ options: ['always'],
+ output: 'type X = { [a :(b)] :(c) }'
+ },
+ {
+ code: 'type X = { [a : (b)] : (c) }',
+ errors: [
+ {message: 'There must be no space before type annotation colon.'},
+ {message: 'There must be no space before type annotation colon.'}
+ ],
+ options: ['never'],
+ output: 'type X = { [a: (b)]: (c) }'
+ }
+ ],
+ valid: [
+ {
+ code: 'type X = { [a : b] : c }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { [a:b]:c }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { +[a : b] : c }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { +[a:b]:c }',
+ options: ['never']
+ },
+ {
+ code: 'type X = { [a : (b)] : (c) }',
+ options: ['always']
+ },
+ {
+ code: 'type X = { [a:(b)]:(c) }',
+ options: ['never']
+ }
+ ]
+};
+
+const TYPE_CAST_EXPRESSIONS = {
+ invalid: [
+ {
+ code: 'const x = ({} :{})',
+ errors: [{message: 'There must be no space before type cast colon.'}],
+ options: ['never'],
+ output: 'const x = ({}:{})'
+ },
+ {
+ code: 'const x = ({}:{})',
+ errors: [{message: 'There must be a space before type cast colon.'}],
+ options: ['always'],
+ output: 'const x = ({} :{})'
+ },
+ {
+ code: 'const x = ({} :{})',
+ errors: [{message: 'There must be 1 space before type cast colon.'}],
+ options: ['always'],
+ output: 'const x = ({} :{})'
+ },
+ {
+ code: '((x) : string)',
+ errors: [{message: 'There must be no space before type cast colon.'}],
+ options: ['never'],
+ output: '((x): string)'
+ },
+ {
+ code: '((x): string)',
+ errors: [{message: 'There must be a space before type cast colon.'}],
+ options: ['always'],
+ output: '((x) : string)'
+ },
+ {
+ code: '((x) : string)',
+ errors: [{message: 'There must be 1 space before type cast colon.'}],
+ options: ['always'],
+ output: '((x) : string)'
+ }
+ ],
+ valid: [
+ {
+ code: 'const x = ({}:{})',
+ options: ['never']
+ },
+ {
+ code: 'const x = ({} :{})',
+ options: ['always']
+ },
+ {
+ code: '((x): string)',
+ options: ['never']
+ },
+ {
+ code: '((x) : string)',
+ options: ['always']
+ }
+ ]
+};
+
+const ALL = [
+ ARROW_FUNCTION_PARAMS,
+ ARROW_FUNCTION_RETURN,
+ FUNCTION_PARAMS,
+ FUNCTION_RETURN,
+ FUNCTION_TYPE_PARAMS,
+ CLASS_PROPERTIES,
+ OBJECT_TYPE_PROPERTIES,
+ OBJECT_TYPE_INDEXERS,
+ TYPE_CAST_EXPRESSIONS
+];
+
+export default {
+ invalid: _.flatMap(ALL, (rules) => { return rules.invalid; }),
+ valid: _.flatMap(ALL, (rules) => { return rules.valid; })
+};
diff --git a/tests/rules/assertions/typeIdMatch.js b/tests/rules/assertions/typeIdMatch.js
new file mode 100644
index 0000000..f5cc21c
--- /dev/null
+++ b/tests/rules/assertions/typeIdMatch.js
@@ -0,0 +1,34 @@
+export default {
+ invalid: [
+ {
+ code: 'type foo = {};',
+ errors: [
+ {
+ message: 'Type identifier \'foo\' does not match pattern \'/^([A-Z][a-z0-9]*)+Type$/\'.'
+ }
+ ]
+ },
+ {
+ code: 'type FooType = {};',
+ errors: [
+ {
+ message: 'Type identifier \'FooType\' does not match pattern \'/^foo$/\'.'
+ }
+ ],
+ options: [
+ '^foo$'
+ ]
+ }
+ ],
+ valid: [
+ {
+ code: 'type FooType = {};'
+ },
+ {
+ code: 'type foo = {};',
+ options: [
+ '^foo$'
+ ]
+ }
+ ]
+};
diff --git a/tests/rules/assertions/unionIntersectionSpacing.js b/tests/rules/assertions/unionIntersectionSpacing.js
new file mode 100644
index 0000000..b46274b
--- /dev/null
+++ b/tests/rules/assertions/unionIntersectionSpacing.js
@@ -0,0 +1,202 @@
+const UNION = {
+ invalid: [
+ {
+ code: 'type X = string| number;',
+ errors: [{message: 'There must be a space before union type annotation separator'}],
+ output: 'type X = string | number;'
+ },
+ {
+ code: 'type X = string| number;',
+ errors: [{message: 'There must be a space before union type annotation separator'}],
+ options: ['always'],
+ output: 'type X = string | number;'
+ },
+ {
+ code: 'type X = string |number;',
+ errors: [{message: 'There must be a space after union type annotation separator'}],
+ output: 'type X = string | number;'
+ },
+ {
+ code: 'type X = string|number;',
+ errors: [
+ {message: 'There must be a space before union type annotation separator'},
+ {message: 'There must be a space after union type annotation separator'}
+ ],
+ output: 'type X = string | number;'
+ },
+ {
+ code: 'type X = {x: string}|{y: number};',
+ errors: [
+ {message: 'There must be a space before union type annotation separator'},
+ {message: 'There must be a space after union type annotation separator'}
+ ],
+ output: 'type X = {x: string} | {y: number};'
+ },
+ {
+ code: 'type X = string | number |boolean;',
+ errors: [{message: 'There must be a space after union type annotation separator'}],
+ output: 'type X = string | number | boolean;'
+ },
+ {
+ code: 'type X = string|number|boolean;',
+ errors: [
+ {message: 'There must be a space before union type annotation separator'},
+ {message: 'There must be a space after union type annotation separator'},
+ {message: 'There must be a space before union type annotation separator'},
+ {message: 'There must be a space after union type annotation separator'}
+ ],
+ output: 'type X = string | number | boolean;'
+ },
+ {
+ code: 'type X = (string)| number;',
+ errors: [{message: 'There must be a space before union type annotation separator'}],
+ output: 'type X = (string) | number;'
+ },
+ {
+ code: 'type X = ((string))|(number | foo);',
+ errors: [
+ {message: 'There must be a space before union type annotation separator'},
+ {message: 'There must be a space after union type annotation separator'}
+ ],
+ output: 'type X = ((string)) | (number | foo);'
+ },
+ {
+ code: 'type X = string |number;',
+ errors: [{message: 'There must be no space before union type annotation separator'}],
+ options: ['never'],
+ output: 'type X = string|number;'
+ },
+ {
+ code: 'type X = string| number;',
+ errors: [{message: 'There must be no space after union type annotation separator'}],
+ options: ['never'],
+ output: 'type X = string|number;'
+ }
+ ],
+ valid: [
+ {code: 'type X = string | number;'},
+ {code: 'type X = string | number | boolean;'},
+ {code: 'type X = (string) | number;'},
+ {code: 'type X = ((string)) | (number | foo);'},
+ {
+ code: 'type X = string|number',
+ options: ['never']
+ },
+ {
+ code: 'type X =\n| string\n| number'
+ },
+ {
+ code: [
+ 'function x() {',
+ 'type X =',
+ '| string',
+ '| number',
+ '}'
+ ].join('\n')
+ }
+ ]
+};
+
+const INTERSECTION = {
+ invalid: [
+ {
+ code: 'type X = string& number;',
+ errors: [{message: 'There must be a space before intersection type annotation separator'}],
+ output: 'type X = string & number;'
+ },
+ {
+ code: 'type X = string& number;',
+ errors: [{message: 'There must be a space before intersection type annotation separator'}],
+ options: ['always'],
+ output: 'type X = string & number;'
+ },
+ {
+ code: 'type X = string &number;',
+ errors: [{message: 'There must be a space after intersection type annotation separator'}],
+ output: 'type X = string & number;'
+ },
+ {
+ code: 'type X = {x: string}&{y: number};',
+ errors: [
+ {message: 'There must be a space before intersection type annotation separator'},
+ {message: 'There must be a space after intersection type annotation separator'}
+ ],
+ output: 'type X = {x: string} & {y: number};'
+ },
+ {
+ code: 'type X = string&number;',
+ errors: [
+ {message: 'There must be a space before intersection type annotation separator'},
+ {message: 'There must be a space after intersection type annotation separator'}
+ ],
+ output: 'type X = string & number;'
+ },
+ {
+ code: 'type X = string & number &boolean;',
+ errors: [{message: 'There must be a space after intersection type annotation separator'}],
+ output: 'type X = string & number & boolean;'
+ },
+ {
+ code: 'type X = string&number&boolean;',
+ errors: [
+ {message: 'There must be a space before intersection type annotation separator'},
+ {message: 'There must be a space after intersection type annotation separator'},
+ {message: 'There must be a space before intersection type annotation separator'},
+ {message: 'There must be a space after intersection type annotation separator'}
+ ],
+ output: 'type X = string & number & boolean;'
+ },
+ {
+ code: 'type X = (string)& number;',
+ errors: [{message: 'There must be a space before intersection type annotation separator'}],
+ output: 'type X = (string) & number;'
+ },
+ {
+ code: 'type X = ((string))&(number & foo);',
+ errors: [
+ {message: 'There must be a space before intersection type annotation separator'},
+ {message: 'There must be a space after intersection type annotation separator'}
+ ],
+ output: 'type X = ((string)) & (number & foo);'
+ },
+ {
+ code: 'type X = string &number;',
+ errors: [{message: 'There must be no space before intersection type annotation separator'}],
+ options: ['never'],
+ output: 'type X = string&number;'
+ },
+ {
+ code: 'type X = string& number;',
+ errors: [{message: 'There must be no space after intersection type annotation separator'}],
+ options: ['never'],
+ output: 'type X = string&number;'
+ }
+ ],
+ valid: [
+ {code: 'type X = string & number;'},
+ {code: 'type X = string & number & boolean;'},
+ {code: 'type X = (string) & number;'},
+ {code: 'type X = ((string)) & (number & foo);'},
+ {
+ code: 'type X = string&number',
+ options: ['never']
+ },
+ {
+ code: 'type X =\n& string\n& number'
+ },
+ {
+ code: [
+ 'function x() {',
+ 'type X =',
+ '& string',
+ '& number',
+ '}'
+ ].join('\n')
+ }
+ ]
+};
+
+export default {
+ invalid: [...UNION.invalid, ...INTERSECTION.invalid],
+ valid: [...UNION.valid, ...INTERSECTION.valid]
+};
diff --git a/tests/rules/assertions/useFlowType.js b/tests/rules/assertions/useFlowType.js
new file mode 100644
index 0000000..cccdaba
--- /dev/null
+++ b/tests/rules/assertions/useFlowType.js
@@ -0,0 +1,190 @@
+import {
+ RuleTester
+} from 'eslint';
+import noUnusedVarsRule from 'eslint/lib/rules/no-unused-vars';
+import useFlowType from './../../../src/rules/useFlowType';
+
+const VALID_WITH_USE_FLOW_TYPE = [
+ {
+ code: 'declare class A {}',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'declare function A(): Y',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'declare module A {}',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'declare module A { declare var a: Y }',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'declare var A: Y',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'import type A from "a"; (function<T: A>(): T {})',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: '(function<T: A>(): T {}); import type A from "a"',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'import type {A} from "a"; (function<T: A>(): T {})',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: '(function<T: A>(): T {}); import type {A} from "a"',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: '(function<T: A>(): T {}); import type {a as A} from "a"',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'type A = {}; function x<Y: A>(i: Y) { i }; x()',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'function x<Y: A>(i: Y) { i }; type A = {}; x()',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'type A = {}; function x<Y: A.B.C>(i: Y) { i }; x()',
+ // QualifiedTypeIdentifier -------^
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'function x<Y: A.B.C>(i: Y) { i }; type A = {}; x()',
+ // ^- QualifiedTypeIdentifier
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ }
+];
+
+const ALWAYS_INVALID = [
+ {
+ code: 'type A = Y',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'function x<A>() {}; x()',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ },
+ {
+ code: 'import type A from "a";',
+ errors: [
+ '\'A\' is defined but never used.'
+ ]
+ }
+];
+
+const ALWAYS_VALID = [
+ 'type A = Y; var x: A; x()',
+ 'var x: A; type A = Y; x()',
+ 'type A = Y; function x(a: A) { a() }; x()',
+ 'function x(a: A) { a() }; type A = Y; x()',
+ 'type A = Y; (x: A)',
+ '(x: A); type A = Y',
+ 'function x<A>(): A {}; x()',
+ 'import type A from "a"; (function(): A {})',
+ '(function(): A {}); import type A from "a";',
+ 'declare interface A {}',
+ 'declare type A = {}'
+];
+
+/**
+ * This rule is tested differently than the rest because `RuleTester` is
+ * designed to test rule reporting and use-flow-type doesn't report
+ * anything. use-flow-type suppresses reports from no-unused-vars. So we're
+ * actually testing no-unused-vars's reporting with use-flow-type enabled.
+ */
+{
+ const ruleTester = new RuleTester({
+ parser: 'babel-eslint'
+ });
+
+ ruleTester.run('no-unused-vars must not trigger an error in these cases', noUnusedVarsRule, {
+ invalid: [],
+ valid: ALWAYS_VALID
+ });
+}
+
+{
+ const ruleTester = new RuleTester({
+ parser: 'babel-eslint'
+ });
+
+ ruleTester.run('no-unused-vars must trigger an error in these cases', noUnusedVarsRule, {
+ invalid: [
+ ...ALWAYS_INVALID,
+ ...VALID_WITH_USE_FLOW_TYPE
+ ],
+ valid: []
+ });
+}
+
+{
+ const ruleTester = new RuleTester({
+ parser: 'babel-eslint',
+ rules: {
+ 'use-flow-type': 1
+ }
+ });
+
+ ruleTester.defineRule('use-flow-type', useFlowType);
+ ruleTester.run('use-flow-type must not affect no-unused-vars behavior in these cases', noUnusedVarsRule, {
+ invalid: ALWAYS_INVALID,
+ valid: ALWAYS_VALID
+ });
+}
+
+export default {
+ invalid: [],
+ valid: [
+ ...VALID_WITH_USE_FLOW_TYPE.map((subject) => {
+ return {
+ code: subject.code,
+ rules: {
+ 'no-unused-vars': 1
+ }
+ };
+ })
+ ]
+};
+
diff --git a/tests/rules/assertions/validSyntax.js b/tests/rules/assertions/validSyntax.js
new file mode 100644
index 0000000..3bffe34
--- /dev/null
+++ b/tests/rules/assertions/validSyntax.js
@@ -0,0 +1,13 @@
+export default {
+ invalid: [
+ // removed, as Babylon now prevents the invalid syntax
+ ],
+ valid: [
+ {
+ code: 'function x(foo: string = "1") {}'
+ },
+ {
+ code: 'function x(foo: Type = bar()) {}'
+ }
+ ]
+};
diff --git a/tests/rules/index.js b/tests/rules/index.js
new file mode 100644
index 0000000..011d7af
--- /dev/null
+++ b/tests/rules/index.js
@@ -0,0 +1,51 @@
+import _ from 'lodash';
+import {
+ RuleTester
+} from 'eslint';
+import plugin from './../../src';
+
+const ruleTester = new RuleTester();
+
+const reportingRules = [
+ 'boolean-style',
+ 'define-flow-type',
+ 'delimiter-dangle',
+ 'generic-spacing',
+ 'no-dupe-keys',
+ 'no-weak-types',
+ 'object-type-delimiter',
+ 'require-parameter-type',
+ 'require-return-type',
+ 'require-valid-file-annotation',
+ 'semi',
+ 'sort-keys',
+ 'space-after-type-colon',
+ 'space-before-type-colon',
+ 'space-before-generic-bracket',
+ 'union-intersection-spacing',
+ 'type-id-match',
+ 'use-flow-type',
+ 'valid-syntax'
+];
+
+const parser = require.resolve('babel-eslint');
+
+for (const ruleName of reportingRules) {
+ /* eslint-disable global-require */
+ const assertions = require('./assertions/' + _.camelCase(ruleName));
+ /* eslint-enable global-require */
+
+ assertions.invalid = _.map(assertions.invalid, (assertion) => {
+ assertion.parser = parser;
+
+ return assertion;
+ });
+
+ assertions.valid = _.map(assertions.valid, (assertion) => {
+ assertion.parser = parser;
+
+ return assertion;
+ });
+
+ ruleTester.run(ruleName, plugin.rules[ruleName], assertions);
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-eslint-plugin-flowtype.git
More information about the Pkg-javascript-commits
mailing list