@blumintinc/eslint-plugin-blumint 1.19.19 → 1.19.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js
CHANGED
|
@@ -40,14 +40,20 @@ exports.enforceObjectLiteralAsConst = (0, createRule_1.createRule)({
|
|
|
40
40
|
return false;
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
|
-
* Checks if
|
|
43
|
+
* Checks if the (unwrapped) return argument is an array literal.
|
|
44
|
+
*
|
|
45
|
+
* Arrays returned from React hook callbacks represent memoized data/prop
|
|
46
|
+
* lists (component props, hit lists, tab labels, etc.). Freezing them into
|
|
47
|
+
* readonly tuples via `as const` fights the mutable/`readonly`-array types
|
|
48
|
+
* they flow into downstream, so any array returned from a hook is exempt —
|
|
49
|
+
* regardless of whether its elements are inline object literals (`[{...}]`),
|
|
50
|
+
* identifier/member references to objects (`[ANY_GAME_HIT]`,
|
|
51
|
+
* `[constants.HIT]`), or primitives. The rule has no type information, so it
|
|
52
|
+
* cannot narrow this further without reintroducing the false positives
|
|
53
|
+
* issues #511 and #1324 document.
|
|
44
54
|
*/
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
// Check if any element in the array is an object literal
|
|
50
|
-
return node.elements.some((elem) => elem !== null && elem.type === 'ObjectExpression');
|
|
55
|
+
function isArrayLiteral(node) {
|
|
56
|
+
return node.type === 'ArrayExpression';
|
|
51
57
|
}
|
|
52
58
|
return {
|
|
53
59
|
ReturnStatement(node) {
|
|
@@ -96,9 +102,10 @@ exports.enforceObjectLiteralAsConst = (0, createRule_1.createRule)({
|
|
|
96
102
|
argument.elements.some((elem) => elem !== null && elem.type === 'SpreadElement'))) {
|
|
97
103
|
return;
|
|
98
104
|
}
|
|
99
|
-
// Skip arrays
|
|
105
|
+
// Skip arrays returned from React hooks (memoized data/prop lists that
|
|
106
|
+
// must not be frozen into readonly tuples — see #511 and #1324)
|
|
100
107
|
if (isInsideReactHook(ancestors) &&
|
|
101
|
-
|
|
108
|
+
isArrayLiteral(argument.type === 'TSAsExpression'
|
|
102
109
|
? argument.expression
|
|
103
110
|
: argument)) {
|
|
104
111
|
return;
|
|
@@ -177,7 +177,11 @@ exports.preferMapOverConditionalDispatch = (0, createRule_1.createRule)({
|
|
|
177
177
|
}
|
|
178
178
|
let text;
|
|
179
179
|
try {
|
|
180
|
-
|
|
180
|
+
// Pass the expression's TS node as the enclosing declaration so the
|
|
181
|
+
// printer qualifies namespaced symbols to their scoped name (e.g.
|
|
182
|
+
// `JSX.Element`, not the DOM global `Element`) at the fix site.
|
|
183
|
+
const enclosing = esTreeNodeToTSNodeMap.get(expr);
|
|
184
|
+
text = checker.typeToString(widened, enclosing);
|
|
181
185
|
}
|
|
182
186
|
catch {
|
|
183
187
|
return null;
|
|
@@ -192,9 +196,13 @@ exports.preferMapOverConditionalDispatch = (0, createRule_1.createRule)({
|
|
|
192
196
|
}
|
|
193
197
|
return parts.length > 0 ? parts.join(' | ') : null;
|
|
194
198
|
}
|
|
195
|
-
function discriminantTypeText(type) {
|
|
199
|
+
function discriminantTypeText(type, discriminant) {
|
|
196
200
|
try {
|
|
197
|
-
|
|
201
|
+
// Pass the discriminant's TS node as the enclosing declaration so the
|
|
202
|
+
// printer qualifies namespaced symbols to their scoped name at the fix
|
|
203
|
+
// site rather than printing an ambiguous short name.
|
|
204
|
+
const enclosing = esTreeNodeToTSNodeMap.get(discriminant);
|
|
205
|
+
const text = checker.typeToString(type, enclosing);
|
|
198
206
|
return text && text !== 'error' ? text : null;
|
|
199
207
|
}
|
|
200
208
|
catch {
|
|
@@ -542,7 +550,7 @@ exports.preferMapOverConditionalDispatch = (0, createRule_1.createRule)({
|
|
|
542
550
|
if (literalKeys.length === 0 || hasOther) {
|
|
543
551
|
return null;
|
|
544
552
|
}
|
|
545
|
-
const dText = discriminantTypeText(type);
|
|
553
|
+
const dText = discriminantTypeText(type, discriminant);
|
|
546
554
|
if (!dText) {
|
|
547
555
|
return null;
|
|
548
556
|
}
|
package/package.json
CHANGED
package/release-manifest.json
CHANGED
|
@@ -1,4 +1,32 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "1.19.21",
|
|
4
|
+
"date": "2026-07-21T21:24:23.464Z",
|
|
5
|
+
"rules": [
|
|
6
|
+
{
|
|
7
|
+
"name": "enforce-object-literal-as-const",
|
|
8
|
+
"changeType": "fix",
|
|
9
|
+
"issues": [
|
|
10
|
+
1324
|
|
11
|
+
],
|
|
12
|
+
"summary": "exempt identifier/member array elements returned from hooks (closes #1324)"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"version": "1.19.20",
|
|
18
|
+
"date": "2026-07-18T20:26:20.204Z",
|
|
19
|
+
"rules": [
|
|
20
|
+
{
|
|
21
|
+
"name": "prefer-map-over-conditional-dispatch",
|
|
22
|
+
"changeType": "fix",
|
|
23
|
+
"issues": [
|
|
24
|
+
1322
|
|
25
|
+
],
|
|
26
|
+
"summary": "qualify JSX value/discriminant type via enclosingDeclaration (closes #1322)"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
2
30
|
{
|
|
3
31
|
"version": "1.19.19",
|
|
4
32
|
"date": "2026-07-18T17:27:38.611Z",
|