tslint-immutable
Version:
TSLint rules to disable mutation in TypeScript.
156 lines • 5.99 kB
JavaScript
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
;