Skip to content

Commit

Permalink
feat: add no-mutable-array rule (#236) (#279)
Browse files Browse the repository at this point in the history
* feat: Add `require-read-only-array` rule (#236)

This rule enforces use of `$ReadOnlyArray` instead of `Array` or array
shorthand notation.

* feat: Rename the rule to `no-mutable-array`
  • Loading branch information
pnevyk authored and gajus committed Oct 6, 2017
1 parent 9c69e90 commit 8a08fcd
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 0 deletions.
1 change: 1 addition & 0 deletions .README/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ When `true`, only checks files with a [`@flow` annotation](http://flowtype.org/d
{"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-mutable-array.md"}
{"gitdown": "include", "file": "./rules/no-primitive-constructor-types.md"}
{"gitdown": "include", "file": "./rules/no-types-missing-file-annotation.md"}
{"gitdown": "include", "file": "./rules/no-unused-expressions.md"}
Expand Down
16 changes: 16 additions & 0 deletions .README/rules/no-mutable-array.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### `no-mutable-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

<!-- assertions noMutableArray -->
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import defineFlowType from './rules/defineFlowType';
import delimiterDangle from './rules/delimiterDangle';
import genericSpacing from './rules/genericSpacing';
import noDupeKeys from './rules/noDupeKeys';
import noMutableArray from './rules/noMutableArray';
import noPrimitiveConstructorTypes from './rules/noPrimitiveConstructorTypes';
import noTypesMissingFileAnnotation from './rules/noTypesMissingFileAnnotation';
import noUnusedExpressions from './rules/noUnusedExpressions';
Expand All @@ -31,6 +32,7 @@ const rules = {
'delimiter-dangle': delimiterDangle,
'generic-spacing': genericSpacing,
'no-dupe-keys': noDupeKeys,
'no-mutable-array': noMutableArray,
'no-primitive-constructor-types': noPrimitiveConstructorTypes,
'no-types-missing-file-annotation': noTypesMissingFileAnnotation,
'no-unused-expressions': noUnusedExpressions,
Expand Down Expand Up @@ -71,6 +73,7 @@ export default {
'delimiter-dangle': 0,
'generic-spacing': 0,
'no-dupe-keys': 0,
'no-mutable-array': 0,
'no-weak-types': 0,
'object-type-delimiter': 0,
'require-parameter-type': 0,
Expand Down
33 changes: 33 additions & 0 deletions src/rules/noMutableArray.js
Original file line number Diff line number Diff line change
@@ -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
};
19 changes: 19 additions & 0 deletions tests/rules/assertions/noMutableArray.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export default {
invalid: [
{
code: 'type X = Array<string>',
errors: [{message: 'Use "$ReadOnlyArray" instead of "Array"'}],
output: 'type X = $ReadOnlyArray<string>'
},
{
code: 'type X = string[]',
errors: [{message: 'Use "$ReadOnlyArray" instead of array shorthand notation'}],
output: 'type X = $ReadOnlyArray<string>'
}
],
valid: [
{
code: 'type X = $ReadOnlyArray<string>'
}
]
};
1 change: 1 addition & 0 deletions tests/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const reportingRules = [
'delimiter-dangle',
'generic-spacing',
'no-dupe-keys',
'no-mutable-array',
'no-primitive-constructor-types',
'no-types-missing-file-annotation',
'no-unused-expressions',
Expand Down

0 comments on commit 8a08fcd

Please sign in to comment.