tslint-immutable
Advanced tools
Comparing version 4.6.0 to 4.7.0
@@ -10,2 +10,12 @@ # Change Log | ||
## [v4.7.0] - 2018-08-23 | ||
### Added | ||
* New option `ignore-mutation-following-accessor` for the `no-array-mutation` rule. See [#88](https://github.com/jonaskello/tslint-immutable/issues/88). Thanks to [@RebeccaStevens](https://github.com/RebeccaStevens) for adding this option! (See PR [#89](https://github.com/jonaskello/tslint-immutable/pull/89)) | ||
* New rules `no-throw` and `no-try`. See [#86](https://github.com/jonaskello/tslint-immutable/issues/86). Thanks to [@RebeccaStevens](https://github.com/RebeccaStevens) for adding these rules! (See PR [#91](https://github.com/jonaskello/tslint-immutable/pull/91)) | ||
* Option for enabling all the rules with `tslint-immutable/all`. See [#66](https://github.com/jonaskello/tslint-immutable/issues/66). Thanks to [@bakerface](https://github.com/bakerface) for adding this! (See PR [#85](https://github.com/jonaskello/tslint-immutable/pull/85)) | ||
## [v4.6.0] - 2018-06-12 | ||
@@ -17,2 +27,8 @@ | ||
## [v4.5.4] - 2018-04-17 | ||
* `no-object-mutation` rule, allow class member mutation in constructor [#79](https://github.com/jonaskello/tslint-immutable/pull/79). | ||
* `readonly-keyword` rule, check function params and return type [#80](https://github.com/jonaskello/tslint-immutable/pull/80) | ||
## [v4.5.3] - 2018-03-31 | ||
@@ -258,3 +274,4 @@ | ||
[unreleased]: https://github.com/jonaskello/tslint-immutable/compare/v4.6.0...master | ||
[v4.6.0]: https://github.com/jonaskello/tslint-immutable/compare/v4.5.3...v4.6.0 | ||
[v4.6.0]: https://github.com/jonaskello/tslint-immutable/compare/v4.5.4...v4.6.0 | ||
[v4.5.4]: https://github.com/jonaskello/tslint-immutable/compare/v4.5.3...v4.5.4 | ||
[v4.5.3]: https://github.com/jonaskello/tslint-immutable/compare/v4.5.2...v4.5.3 | ||
@@ -261,0 +278,0 @@ [v4.5.2]: https://github.com/jonaskello/tslint-immutable/compare/v4.5.1...v4.5.2 |
{ | ||
"name": "tslint-immutable", | ||
"version": "4.6.0", | ||
"version": "4.7.0", | ||
"description": "TSLint rules to disable mutation in TypeScript.", | ||
@@ -38,3 +38,3 @@ "main": "tslint-immutable.json", | ||
"test": "tslint --test test/rules/**/*", | ||
"test:work": "yarn build && tslint --test test/rules/no-array-mutation/**/*", | ||
"test:work": "yarn build && tslint --test test/rules/no-try/**/*", | ||
"verify": "yarn build && yarn lint && yarn coverage", | ||
@@ -41,0 +41,0 @@ "coverage": "rimraf coverage .nyc_output && nyc yarn test", |
@@ -52,2 +52,4 @@ # tslint-immutable | ||
* [no-loop-statement](#no-loop-statement) | ||
* [no-throw](#no-throw) | ||
* [no-try](#no-try) | ||
* [Recommended built-in rules](#recommended-built-in-rules) | ||
@@ -250,2 +252,3 @@ | ||
* [ignore-prefix](#using-the-ignore-prefix-option) | ||
* [ignore-mutation-following-accessor](#using-the-ignore-mutation-following-accessor-option-with-no-array-mutation) | ||
@@ -262,2 +265,6 @@ #### Example config | ||
```javascript | ||
"no-array-mutation": [true, "ignore-mutation-following-accessor"] | ||
``` | ||
### no-object-mutation | ||
@@ -430,2 +437,34 @@ | ||
### no-throw | ||
Exceptions are not part of functional programming. | ||
```typescript | ||
throw new Error("Something went wrong."); // Unexpected throw, throwing exceptions is not functional. | ||
``` | ||
As an alternative a function should return an error: | ||
```typescript | ||
function divide(x: number, y: number): number | Error { | ||
return y === 0 ? new Error("Cannot divide by zero.") : x / y; | ||
} | ||
``` | ||
Or in the case of an async function, a rejected promise should be returned: | ||
```typescript | ||
async function divide(x: Promise<number>, y: Promise<number>): Promise<number> { | ||
const [xv, yv] = await Promise.all([x, y]); | ||
return yv === 0 | ||
? Promise.reject(new Error("Cannot divide by zero.")) | ||
: xv / yv; | ||
} | ||
``` | ||
### no-try | ||
Try statements are not part of functional programming. See [no-throw](#no-throw) for more information. | ||
## Options | ||
@@ -489,2 +528,12 @@ | ||
### Using the `ignore-mutation-following-accessor` option with `no-array-mutation` | ||
This option allows for the use of array mutator methods to be chained to an array accessor method (methods that modify the original array are known as [mutator methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Mutator_methods) (eg. `sort`) and methods that return a copy are known as [accessor methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Accessor_methods) (eg. `slice` and `concat`)). | ||
For example, an array can be immutably sorted with a single line like so: | ||
```typescript | ||
const sorted = ["foo", "bar"].slice().sort((a, b) => a.localeCompare(b)); // This is OK with ignore-mutation-following-accessor | ||
``` | ||
## Recommended built-in rules | ||
@@ -522,5 +571,3 @@ | ||
{ | ||
"extends": [ | ||
"tslint-immutable" | ||
], | ||
"extends": ["tslint-immutable"], | ||
"rules": { | ||
@@ -552,2 +599,10 @@ | ||
It is also possible to enable all the rules in tslint-immutable by extending `tslint-immutable/all` like this: | ||
```javascript | ||
{ | ||
"extends": ["tslint-immutable/all"] | ||
} | ||
``` | ||
## How to contribute | ||
@@ -554,0 +609,0 @@ |
@@ -31,3 +31,8 @@ "use strict"; | ||
]; | ||
var forbidMethods = [ | ||
/** | ||
* Methods that mutate an array. | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Methods#Mutator_methods | ||
*/ | ||
var mutatorMethods = [ | ||
"copyWithin", | ||
@@ -43,2 +48,12 @@ "fill", | ||
]; | ||
/** | ||
* Methods that return a new array without mutating the original. | ||
* | ||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Methods#Accessor_methods | ||
*/ | ||
var accessorMethods = [ | ||
"concat", | ||
"slice", | ||
"toSource" // TODO: This is a non standardized method, should it me including? | ||
]; | ||
function isArrayType(type) { | ||
@@ -136,4 +151,7 @@ return type.symbol !== undefined && type.symbol.name === "Array"; | ||
var propAccExp_1 = callExp.expression; | ||
if (forbidMethods.some(function (m) { return m === propAccExp_1.name.text; }) && | ||
!Ignore.isIgnoredPrefix(callExp.getText(node.getSourceFile()), ctx.options.ignorePrefix)) { | ||
if (mutatorMethods.some(function (m) { return m === propAccExp_1.name.text; }) && | ||
!Ignore.isIgnoredPrefix(callExp.getText(node.getSourceFile()), ctx.options.ignorePrefix) && | ||
(!ctx.options.ignoreMutationFollowingAccessor || | ||
!isInChainCallAndFollowsAccessor(propAccExp_1))) { | ||
// Do the type checking as late as possible (as it is expensive). | ||
var expressionType = checker.getTypeAtLocation(propAccExp_1.expression); | ||
@@ -147,2 +165,20 @@ if (isArrayType(expressionType)) { | ||
} | ||
/** | ||
* Check if the given the given PropertyAccessExpression is part of a chain and | ||
* immediately follows an accessor method call. | ||
* | ||
* If this is the case, then the given PropertyAccessExpression is allowed to be a mutator method call. | ||
*/ | ||
function isInChainCallAndFollowsAccessor(propAccExp) { | ||
if (ts.SyntaxKind.CallExpression === propAccExp.expression.kind) { | ||
var subCallExp = propAccExp.expression; | ||
if (ts.SyntaxKind.PropertyAccessExpression === subCallExp.expression.kind) { | ||
var subPropAccExp_1 = subCallExp.expression; | ||
if (accessorMethods.some(function (m) { return m === subPropAccExp_1.name.text; })) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
//# sourceMappingURL=noArrayMutationRule.js.map |
@@ -10,3 +10,3 @@ "use strict"; | ||
function checkNode(node, ctx) { | ||
var variableStatementFailures = chectVariableStatement(node, ctx); | ||
var variableStatementFailures = checkVariableStatement(node, ctx); | ||
var forStatementsFailures = checkForStatements(node, ctx); | ||
@@ -17,3 +17,3 @@ return { | ||
} | ||
function chectVariableStatement(node, ctx) { | ||
function checkVariableStatement(node, ctx) { | ||
if (node.kind === ts.SyntaxKind.VariableStatement) { | ||
@@ -29,8 +29,8 @@ var variableStatementNode = node; | ||
node.kind === ts.SyntaxKind.ForOfStatement) { | ||
var forStatmentNode = node; | ||
if (forStatmentNode.initializer && | ||
forStatmentNode.initializer.kind === | ||
var forStatementNode = node; | ||
if (forStatementNode.initializer && | ||
forStatementNode.initializer.kind === | ||
ts.SyntaxKind.VariableDeclarationList && | ||
Lint.isNodeFlagSet(forStatmentNode.initializer, ts.NodeFlags.Let)) { | ||
var declarationList = forStatmentNode.initializer; | ||
Lint.isNodeFlagSet(forStatementNode.initializer, ts.NodeFlags.Let)) { | ||
var declarationList = forStatementNode.initializer; | ||
return checkDeclarationList(declarationList, ctx); | ||
@@ -37,0 +37,0 @@ } |
@@ -45,6 +45,6 @@ /** | ||
} | ||
// Use return becuase performance hints docs say it optimizes the function using tail-call recursion | ||
// Use return because performance hints docs say it optimizes the function using tail-call recursion | ||
return ts.forEachChild(node, cb); | ||
}; | ||
// Check either the parameter's explicit type if it has one, or itself for implict type | ||
// Check either the parameter's explicit type if it has one, or itself for implicit type | ||
for (var _i = 0, _a = functionNode.parameters.map(function (p) { return (p.type ? p.type : p); }); _i < _a.length; _i++) { | ||
@@ -51,0 +51,0 @@ var n = _a[_i]; |
@@ -43,4 +43,8 @@ "use strict"; | ||
var words = text.split(/[-_]/g); | ||
return words[0].toLowerCase() + words.slice(1).map(upFirst); | ||
return (words[0].toLowerCase() + | ||
words | ||
.slice(1) | ||
.map(upFirst) | ||
.join("")); | ||
} | ||
//# sourceMappingURL=options.js.map |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
624652
95
1903
633