1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | var ts = require("typescript");
|
4 | var utils = require("tsutils/typeguard/2.8");
|
5 | var util_1 = require("tsutils/util");
|
6 | var check_node_1 = require("./shared/check-node");
|
7 | var Ignore = require("./shared/ignore");
|
8 | var typeguard_1 = require("./shared/typeguard");
|
9 |
|
10 | exports.Rule = check_node_1.createCheckNodeTypedRule(checkTypedNode, "Mutating an array is not allowed.");
|
11 | function isArrayType(type) {
|
12 | return Boolean(type.symbol && type.symbol.name === "Array");
|
13 | }
|
14 | exports.isArrayType = isArrayType;
|
15 | function isArrayConstructorType(type) {
|
16 | return Boolean(type.symbol && type.symbol.name === "ArrayConstructor");
|
17 | }
|
18 | exports.isArrayConstructorType = isArrayConstructorType;
|
19 | var forbidUnaryOps = [
|
20 | ts.SyntaxKind.PlusPlusToken,
|
21 | ts.SyntaxKind.MinusMinusToken
|
22 | ];
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | var mutatorMethods = [
|
29 | "copyWithin",
|
30 | "fill",
|
31 | "pop",
|
32 | "push",
|
33 | "reverse",
|
34 | "shift",
|
35 | "sort",
|
36 | "splice",
|
37 | "unshift"
|
38 | ];
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 | var newArrayReturningMethods = [
|
46 | "concat",
|
47 | "slice",
|
48 | "filter",
|
49 | "map",
|
50 | "reduce",
|
51 | "reduceRight"
|
52 | ];
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | var constructorFunctions = ["from", "of"];
|
59 | function checkTypedNode(node, ctx, checker) {
|
60 | return { invalidNodes: getInvalidNodes(node, ctx, checker) };
|
61 | }
|
62 | function getInvalidNodes(node, ctx, checker) {
|
63 | if (utils.isBinaryExpression(node)) {
|
64 | return checkBinaryExpression(node, ctx, checker);
|
65 | }
|
66 | if (utils.isDeleteExpression(node)) {
|
67 | return checkDeleteExpression(node, ctx, checker);
|
68 | }
|
69 | if (utils.isPrefixUnaryExpression(node)) {
|
70 | return checkPrefixUnaryExpression(node, ctx, checker);
|
71 | }
|
72 | if (utils.isPostfixUnaryExpression(node)) {
|
73 | return checkPostfixUnaryExpression(node, ctx, checker);
|
74 | }
|
75 | if (utils.isCallExpression(node)) {
|
76 | return checkCallExpression(node, ctx, checker);
|
77 | }
|
78 | return [];
|
79 | }
|
80 |
|
81 |
|
82 |
|
83 |
|
84 | function checkBinaryExpression(node, ctx, checker) {
|
85 | if (!Ignore.isIgnoredPrefix(node.getText(node.getSourceFile()), ctx.options.ignorePrefix) &&
|
86 | utils.isBinaryExpression(node) &&
|
87 | util_1.isAssignmentKind(node.operatorToken.kind) &&
|
88 | typeguard_1.isAccessExpression(node.left)) {
|
89 | var leftExpressionType = checker.getTypeAtLocation(node.left.expression);
|
90 | if (isArrayType(leftExpressionType)) {
|
91 | return [check_node_1.createInvalidNode(node, [])];
|
92 | }
|
93 | }
|
94 | return [];
|
95 | }
|
96 |
|
97 |
|
98 |
|
99 | function checkDeleteExpression(node, ctx, checker) {
|
100 | if (!Ignore.isIgnoredPrefix(node.expression.getText(node.getSourceFile()), ctx.options.ignorePrefix) &&
|
101 | typeguard_1.isAccessExpression(node.expression)) {
|
102 | var expressionType = checker.getTypeAtLocation(node.expression.expression);
|
103 | if (isArrayType(expressionType)) {
|
104 | return [check_node_1.createInvalidNode(node, [])];
|
105 | }
|
106 | }
|
107 | return [];
|
108 | }
|
109 |
|
110 |
|
111 |
|
112 | function checkPrefixUnaryExpression(node, ctx, checker) {
|
113 | if (!Ignore.isIgnoredPrefix(node.operand.getText(node.getSourceFile()), ctx.options.ignorePrefix) &&
|
114 | typeguard_1.isAccessExpression(node.operand) &&
|
115 | forbidUnaryOps.some(function (o) { return o === node.operator; })) {
|
116 | var operandExpressionType = checker.getTypeAtLocation(node.operand.expression);
|
117 | if (isArrayType(operandExpressionType)) {
|
118 | return [check_node_1.createInvalidNode(node, [])];
|
119 | }
|
120 | }
|
121 | return [];
|
122 | }
|
123 |
|
124 |
|
125 |
|
126 | function checkPostfixUnaryExpression(node, ctx, checker) {
|
127 | if (!Ignore.isIgnoredPrefix(node.getText(node.getSourceFile()), ctx.options.ignorePrefix) &&
|
128 | typeguard_1.isAccessExpression(node.operand) &&
|
129 | forbidUnaryOps.some(function (o) { return o === node.operator; })) {
|
130 | var operandExpressionType = checker.getTypeAtLocation(node.operand.expression);
|
131 | if (isArrayType(operandExpressionType)) {
|
132 | return [check_node_1.createInvalidNode(node, [])];
|
133 | }
|
134 | }
|
135 | return [];
|
136 | }
|
137 |
|
138 |
|
139 |
|
140 | function checkCallExpression(node, ctx, checker) {
|
141 | if (!Ignore.isIgnoredPrefix(node.getText(node.getSourceFile()), ctx.options.ignorePrefix) &&
|
142 | utils.isPropertyAccessExpression(node.expression) &&
|
143 | (!(ctx.options.ignoreNewArray || ctx.options.ignoreMutationFollowingAccessor) ||
|
144 | !isInChainCallAndFollowsNew(node.expression, checker)) &&
|
145 | mutatorMethods.some(function (m) { return m === node.expression.name.text; })) {
|
146 |
|
147 | var expressionType = checker.getTypeAtLocation(node.expression.expression);
|
148 | if (isArrayType(expressionType)) {
|
149 | return [check_node_1.createInvalidNode(node, [])];
|
150 | }
|
151 | }
|
152 | return [];
|
153 | }
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 | function isInChainCallAndFollowsNew(node, checker) {
|
161 | return (utils.isArrayLiteralExpression(node.expression) ||
|
162 | (utils.isNewExpression(node.expression) &&
|
163 | isArrayConstructorType(checker.getTypeAtLocation(node.expression.expression))) ||
|
164 | (utils.isCallExpression(node.expression) &&
|
165 | utils.isPropertyAccessExpression(node.expression.expression) &&
|
166 | constructorFunctions.some(isExpected(node.expression.expression.name.text)) &&
|
167 | isArrayConstructorType(checker.getTypeAtLocation(node.expression.expression.expression))) ||
|
168 | (utils.isCallExpression(node.expression) &&
|
169 | utils.isPropertyAccessExpression(node.expression.expression) &&
|
170 | newArrayReturningMethods.some(isExpected(node.expression.expression.name.text))));
|
171 | }
|
172 |
|
173 |
|
174 |
|
175 | function isExpected(expected) {
|
176 | return function (actual) { return actual === expected; };
|
177 | }
|
178 |
|
\ | No newline at end of file |