UNPKG

tslint-immutable

Version:

TSLint rules to disable mutation in TypeScript.

156 lines 5.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var ts = require("typescript"); var Lint = require("tslint"); var utils = require("tsutils/typeguard/2.8"); var Ignore = require("./shared/ignore"); var check_node_1 = require("./shared/check-node"); var typeguard_1 = require("./shared/typeguard"); // tslint:disable-next-line:variable-name exports.Rule = check_node_1.createCheckNodeRule(Ignore.checkNodeWithIgnore(checkNode), "Only ReadonlyArray allowed."); function checkNode(node, ctx) { var results = [ checkArrayType(node, ctx), checkTypeReference(node, ctx), checkImplicitType(node, ctx), checkTupleType(node, ctx) ]; return { invalidNodes: results.reduce(function (merged, result) { return merged.concat(result.invalidNodes); }, []), skipChildren: results.some(function (result) { return result.skipChildren === true; }) }; } function checkArrayType(node, ctx) { // We need to check both shorthand syntax "number[]"... if (utils.isArrayTypeNode(node)) { // Ignore arrays decleared with readonly keyword. if (node.parent && utils.isTypeOperatorNode(node.parent) && node.parent.operator === ts.SyntaxKind.ReadonlyKeyword) { return { invalidNodes: [] }; } if (node.parent && Ignore.shouldIgnorePrefix(node.parent, ctx.options, ctx.sourceFile)) { return { invalidNodes: [], skipChildren: true }; } if (ctx.options.ignoreRestParameters && node.parent && utils.isParameterDeclaration(node.parent) && node.parent.dotDotDotToken) { return { invalidNodes: [] }; } if (ctx.options.ignoreReturnType && checkIsReturnTypeOrNestedWithIn(node)) { return { invalidNodes: [] }; } var _a = ts.version .split(".") .map(function (n) { return Number.parseInt(n, 10); }), major = _a[0], minor = _a[1]; return { invalidNodes: [ check_node_1.createInvalidNode(node, major > 3 || (major === 3 && minor >= 4) ? getReadonlyKeywordFix(node, ctx) : getReadonlyArrayFix(node, ctx)) ] }; } return { invalidNodes: [] }; } function checkTypeReference(node, ctx) { // ...and type reference "Array<number>" if (utils.isTypeReferenceNode(node) && node.typeName.getText(ctx.sourceFile) === "Array") { if (node.parent && Ignore.shouldIgnorePrefix(node.parent, ctx.options, ctx.sourceFile)) { return { invalidNodes: [], skipChildren: true }; } if (ctx.options.ignoreReturnType && checkIsReturnTypeOrNestedWithIn(node)) { return { invalidNodes: [] }; } return { invalidNodes: [ check_node_1.createInvalidNode(node, [ new Lint.Replacement(node.getStart(ctx.sourceFile), 0, "Readonly") ]) ] }; } return { invalidNodes: [] }; } function checkImplicitType(node, ctx) { if (Ignore.shouldIgnorePrefix(node, ctx.options, ctx.sourceFile)) { return { invalidNodes: [], skipChildren: true }; } // Check if the initializer is used to set an implicit array type if (typeguard_1.isVariableOrParameterOrPropertyDeclaration(node) && isUntypedAndHasArrayLiteralExpressionInitializer(node)) { var length_1 = node.name.getWidth(ctx.sourceFile); var nameText = node.name.getText(ctx.sourceFile); var typeArgument = "any"; return { invalidNodes: [ check_node_1.createInvalidNode(node.name, [ new Lint.Replacement(node.name.end - length_1, length_1, nameText + ": ReadonlyArray<" + typeArgument + ">") ]) ] }; } return { invalidNodes: [] }; } exports.checkImplicitType = checkImplicitType; function checkIsReturnTypeOrNestedWithIn(node) { return node.parent ? typeguard_1.isFunctionLikeDeclaration(node.parent) && node === node.parent.type ? true : checkIsReturnTypeOrNestedWithIn(node.parent) : false; } function isUntypedAndHasArrayLiteralExpressionInitializer(node) { return Boolean(!node.type && (node.initializer && utils.isArrayLiteralExpression(node.initializer))); } function checkTupleType(node, ctx) { var _a = ts.version.split(".").map(function (n) { return Number.parseInt(n, 10); }), major = _a[0], minor = _a[1]; // Only applies to ts 3.4 and newer. if (major > 3 || (major === 3 && minor >= 4)) { if (utils.isTupleTypeNode(node)) { // Ignore arrays decleared with readonly keyword. if (node.parent && utils.isTypeOperatorNode(node.parent) && node.parent.operator === ts.SyntaxKind.ReadonlyKeyword) { return { invalidNodes: [] }; } return { invalidNodes: [ check_node_1.createInvalidNode(node, getReadonlyKeywordFix(node, ctx)) ] }; } } return { invalidNodes: [] }; } function getReadonlyKeywordFix(node, ctx) { // Nested shorthand syntax array? if (utils.isArrayTypeNode(node.parent)) { return [ new Lint.Replacement(node.getStart(ctx.sourceFile), 0, "(readonly "), new Lint.Replacement(node.end, 0, ")") ]; } return [new Lint.Replacement(node.getStart(ctx.sourceFile), 0, "readonly ")]; } function getReadonlyArrayFix(node, ctx) { return [ new Lint.Replacement(node.getStart(ctx.sourceFile), 0, "ReadonlyArray<"), new Lint.Replacement(node.end - 2, 2, ">") ]; } //# sourceMappingURL=readonlyArrayRule.js.map