From e659da5226b99d332db5bc6ec12e14d7ff25ea47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Nevyho=C5=A1t=C4=9Bn=C3=BD?= Date: Sun, 1 Oct 2017 18:28:24 +0200 Subject: [PATCH] feat: Add `require-read-only-array` rule (#236) This rule enforces use of `$ReadOnlyArray` instead of `Array` or array shorthand notation. --- .README/README.md | 1 + .README/rules/require-read-only-array.md | 16 +++++++++ src/index.js | 3 ++ src/rules/requireReadOnlyArray.js | 33 +++++++++++++++++++ .../rules/assertions/requireReadOnlyArray.js | 19 +++++++++++ tests/rules/index.js | 1 + 6 files changed, 73 insertions(+) create mode 100644 .README/rules/require-read-only-array.md create mode 100644 src/rules/requireReadOnlyArray.js create mode 100644 tests/rules/assertions/requireReadOnlyArray.js diff --git a/.README/README.md b/.README/README.md index 665c5a9c..59536185 100644 --- a/.README/README.md +++ b/.README/README.md @@ -153,6 +153,7 @@ When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/d {"gitdown": "include", "file": "./rules/no-weak-types.md"} {"gitdown": "include", "file": "./rules/object-type-delimiter.md"} {"gitdown": "include", "file": "./rules/require-parameter-type.md"} +{"gitdown": "include", "file": "./rules/require-read-only-array.md"} {"gitdown": "include", "file": "./rules/require-return-type.md"} {"gitdown": "include", "file": "./rules/require-valid-file-annotation.md"} {"gitdown": "include", "file": "./rules/require-variable-type.md"} diff --git a/.README/rules/require-read-only-array.md b/.README/rules/require-read-only-array.md new file mode 100644 index 00000000..3d6ed904 --- /dev/null +++ b/.README/rules/require-read-only-array.md @@ -0,0 +1,16 @@ +### `require-read-only-array` + +_The `--fix` option on the command line automatically fixes problems reported by this rule._ + +Requires use of [`$ReadOnlyArray`](https://github.com/facebook/flow/blob/v0.46.0/lib/core.js#L185) instead of just `Array` or array [shorthand notation](https://flow.org/en/docs/types/arrays/#toc-array-type-shorthand-syntax). `$ReadOnlyArray` is immutable array collection type and the superclass of Array and tuple types in Flow. Use of `$ReadOnlyArray` instead of `Array` can solve some "problems" in typing with Flow (e.g., [1](https://github.com/facebook/flow/issues/3425), [2](https://github.com/facebook/flow/issues/4251)). + +General reasons for using immutable data structures: + +* They are simpler to construct, test, and use +* They help to avoid temporal coupling +* Their usage is side-effect free (no defensive copies) +* Identity mutability problem is avoided +* They always have failure atomicity +* They are much easier to cache + + diff --git a/src/index.js b/src/index.js index 26e2fbc1..ebea398c 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,7 @@ import noUnusedExpressions from './rules/noUnusedExpressions'; import noWeakTypes from './rules/noWeakTypes'; import objectTypeDelimiter from './rules/objectTypeDelimiter'; import requireParameterType from './rules/requireParameterType'; +import requireReadOnlyArray from './rules/requireReadOnlyArray'; import requireReturnType from './rules/requireReturnType'; import requireValidFileAnnotation from './rules/requireValidFileAnnotation'; import requireVariableType from './rules/requireVariableType'; @@ -37,6 +38,7 @@ const rules = { 'no-weak-types': noWeakTypes, 'object-type-delimiter': objectTypeDelimiter, 'require-parameter-type': requireParameterType, + 'require-read-only-array': requireReadOnlyArray, 'require-return-type': requireReturnType, 'require-valid-file-annotation': requireValidFileAnnotation, 'require-variable-type': requireVariableType, @@ -74,6 +76,7 @@ export default { 'no-weak-types': 0, 'object-type-delimiter': 0, 'require-parameter-type': 0, + 'require-read-only-array': 0, 'require-return-type': 0, 'require-variable-type': 0, semi: 0, diff --git a/src/rules/requireReadOnlyArray.js b/src/rules/requireReadOnlyArray.js new file mode 100644 index 00000000..fa86da3d --- /dev/null +++ b/src/rules/requireReadOnlyArray.js @@ -0,0 +1,33 @@ +const schema = []; + +const create = (context) => { + return { + ArrayTypeAnnotation (node) { + context.report({ + fix (fixer) { + const rawElementType = context.getSourceCode().getText(node.elementType); + + return fixer.replaceText(node, '$ReadOnlyArray<' + rawElementType + '>'); + }, + message: 'Use "$ReadOnlyArray" instead of array shorthand notation', + node + }); + }, + GenericTypeAnnotation (node) { + if (node.id.name === 'Array') { + context.report({ + fix (fixer) { + return fixer.replaceText(node.id, '$ReadOnlyArray'); + }, + message: 'Use "$ReadOnlyArray" instead of "Array"', + node + }); + } + } + }; +}; + +export default { + create, + schema +}; diff --git a/tests/rules/assertions/requireReadOnlyArray.js b/tests/rules/assertions/requireReadOnlyArray.js new file mode 100644 index 00000000..52fe90be --- /dev/null +++ b/tests/rules/assertions/requireReadOnlyArray.js @@ -0,0 +1,19 @@ +export default { + invalid: [ + { + code: 'type X = Array', + errors: [{message: 'Use "$ReadOnlyArray" instead of "Array"'}], + output: 'type X = $ReadOnlyArray' + }, + { + code: 'type X = string[]', + errors: [{message: 'Use "$ReadOnlyArray" instead of array shorthand notation'}], + output: 'type X = $ReadOnlyArray' + } + ], + valid: [ + { + code: 'type X = $ReadOnlyArray' + } + ] +}; diff --git a/tests/rules/index.js b/tests/rules/index.js index 76394305..7d9148cc 100644 --- a/tests/rules/index.js +++ b/tests/rules/index.js @@ -22,6 +22,7 @@ const reportingRules = [ 'no-weak-types', 'object-type-delimiter', 'require-parameter-type', + 'require-read-only-array', 'require-return-type', 'require-valid-file-annotation', 'require-variable-type',