@fimbul/mimir
Advanced tools
Comparing version 0.24.0-dev.20210120 to 0.24.0-dev.20210121
{ | ||
"name": "@fimbul/mimir", | ||
"version": "0.24.0-dev.20210120", | ||
"version": "0.24.0-dev.20210121", | ||
"description": "Core rules of the Fimbullinter project", | ||
@@ -5,0 +5,0 @@ "main": "recommended.yaml", |
@@ -44,2 +44,3 @@ # Mímir | ||
[`no-nan-compare`](docs/no-nan-compare.md) | Disallows comparing with `NaN`, use `isNaN(number)` or `Number.isNaN(number)` instead. | Performance! | ||
[`no-object-spread-of-iterable`](docs/no-object-spread-of-iterable.md) | :mag: Disallows spreading iterable types into an object. | | ||
[`no-octal-escape`](docs/no-octal-escape.md) | :wrench: Disallows octal escape sequences in strings and template strings. | No such rule in TSLint. | ||
@@ -46,0 +47,0 @@ [`no-restricted-property-access`](docs/no-restricted-property-access.md) | :mag: Disallows accessing properties via computed name that would not be accessible using a static name. | TSLint has no similar rule. |
@@ -6,6 +6,2 @@ import { TypedRule } from '@fimbul/ymir'; | ||
private checkForStatement; | ||
private isIterationPossible; | ||
private isIterationProtocolAvailable; | ||
private isArrayLike; | ||
private isIterable; | ||
} |
@@ -8,3 +8,3 @@ "use strict"; | ||
const tsutils_1 = require("tsutils"); | ||
const utils_1 = require("../utils"); | ||
const iteration_1 = require("../iteration"); | ||
let Rule = class Rule extends ymir_1.TypedRule { | ||
@@ -35,50 +35,5 @@ get usage() { | ||
return; | ||
if (this.isIterationPossible(arrayVariable)) | ||
if (iteration_1.isExpressionIterable(arrayVariable, this.checker, this.context.compilerOptions, true)) | ||
this.addFinding(node.getStart(this.sourceFile), node.statement.pos, `Prefer a 'for-of' loop over a 'for' loop for this simple iteration.`); | ||
} | ||
isIterationPossible(node) { | ||
const type = this.checker.getTypeAtLocation(node); | ||
return this.isIterationProtocolAvailable() | ||
? this.isIterable(this.checker.getApparentType(type), node) | ||
: tsutils_1.unionTypeParts(utils_1.tryGetBaseConstraintType(type, this.checker)).every(this.isArrayLike, this); | ||
} | ||
isIterationProtocolAvailable() { | ||
return this.sourceFile.languageVersion >= ts.ScriptTarget.ES2015 || this.context.compilerOptions.downlevelIteration === true; | ||
} | ||
isArrayLike(type) { | ||
if (tsutils_1.isTypeReference(type)) | ||
type = type.target; | ||
if (type.getNumberIndexType() === undefined) | ||
return false; | ||
if (type.flags & ts.TypeFlags.StringLike) | ||
return this.sourceFile.languageVersion >= ts.ScriptTarget.ES5; // iterating string is only possible starting from ES5 | ||
if (type.symbol !== undefined && /^(Concat|Readonly)?Array$/.test(type.symbol.escapedName) && | ||
type.symbol.declarations !== undefined && type.symbol.declarations.some((node) => node.getSourceFile().hasNoDefaultLib)) | ||
return true; | ||
if (tsutils_1.isIntersectionType(type)) | ||
return type.types.some(this.isArrayLike, this); | ||
const baseTypes = type.getBaseTypes(); | ||
return baseTypes !== undefined && baseTypes.some(this.isArrayLike, this); | ||
} | ||
isIterable(type, node) { | ||
const indexType = type.getNumberIndexType() || type.getStringIndexType(); | ||
if (indexType === undefined) | ||
return false; | ||
const iteratorFn = tsutils_1.getPropertyOfType(type, '__@iterator'); | ||
if (!isPresentPublicAndRequired(iteratorFn)) | ||
return false; | ||
return checkReturnTypeAndRequireZeroArity(this.checker.getTypeOfSymbolAtLocation(iteratorFn, node), (iterator) => { | ||
const next = iterator.getProperty('next'); | ||
return isPresentPublicAndRequired(next) && | ||
checkReturnTypeAndRequireZeroArity(this.checker.getTypeOfSymbolAtLocation(next, node), (iteratorResult) => { | ||
const done = iteratorResult.getProperty('done'); | ||
if (!isPresentAndPublic(done) || | ||
tsutils_1.someTypePart(tsutils_1.removeOptionalityFromType(this.checker, this.checker.getTypeOfSymbolAtLocation(done, node)), tsutils_1.isUnionType, (t) => !tsutils_1.isTypeFlagSet(t, ts.TypeFlags.BooleanLike))) | ||
return false; | ||
const value = tsutils_1.getIteratorYieldResultFromIteratorResult(iteratorResult, node, this.checker).getProperty('value'); | ||
return isPresentAndPublic(value) && | ||
utils_1.typesAreEqual(this.checker.getTypeOfSymbolAtLocation(value, node), indexType, this.checker); | ||
}); | ||
}); | ||
} | ||
}; | ||
@@ -89,39 +44,2 @@ Rule = tslib_1.__decorate([ | ||
exports.Rule = Rule; | ||
function checkReturnTypeAndRequireZeroArity(type, cb) { | ||
let zeroArity = false; | ||
for (const signature of type.getCallSignatures()) { | ||
if (!cb(signature.getReturnType())) | ||
return false; | ||
if (signatureHasArityZero(signature)) | ||
zeroArity = true; | ||
} | ||
return zeroArity; | ||
} | ||
function signatureHasArityZero(signature) { | ||
if (signature.parameters.length === 0) | ||
return true; | ||
const decl = signature.parameters[0].declarations[0]; | ||
return decl !== undefined && isOptionalParameter(decl); | ||
} | ||
function isOptionalParameter(node) { | ||
if (node.questionToken !== undefined || node.dotDotDotToken !== undefined) | ||
return true; | ||
if (node.flags & ts.NodeFlags.JavaScriptFile && ts.getJSDocParameterTags(node).some((tag) => tag.isBracketed)) | ||
return true; | ||
if (node.initializer === undefined) | ||
return false; | ||
const parameters = node.parent.parameters; | ||
const nextIndex = parameters.indexOf(node) + 1; | ||
if (nextIndex === parameters.length) | ||
return true; | ||
return isOptionalParameter(parameters[nextIndex]); | ||
} | ||
function isPresentPublicAndRequired(symbol) { | ||
return isPresentAndPublic(symbol) && !tsutils_1.isSymbolFlagSet(symbol, ts.SymbolFlags.Optional); | ||
} | ||
function isPresentAndPublic(symbol) { | ||
return symbol !== undefined && | ||
(symbol.declarations === undefined || | ||
symbol.declarations.every((d) => (ts.getCombinedModifierFlags(d) & ts.ModifierFlags.NonPublicAccessibilityModifier) === 0)); | ||
} | ||
function isReadonlyArrayAccess(uses, arrayVariable, statement, sourceFile) { | ||
@@ -128,0 +46,0 @@ let arrayAccess = false; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
442314
165
5195
92