@blumintinc/eslint-plugin-blumint 1.20.166 → 1.20.167
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 +1 -1
- package/lib/rules/require-props-composition.js +42 -2
- package/package.json +1 -1
- package/release-manifest.json +14 -0
package/lib/index.js
CHANGED
|
@@ -119,8 +119,8 @@ function getTypeReferenceName(node) {
|
|
|
119
119
|
/**
|
|
120
120
|
* Recursively check if a TS type node composes with the given propsTypeName
|
|
121
121
|
* via Pick/Omit (at any level of intersection / Readonly wrapping, union arm,
|
|
122
|
-
* named-alias indirection, or nested in a TSTypeLiteral
|
|
123
|
-
* annotation).
|
|
122
|
+
* array or tuple element, named-alias indirection, or nested in a TSTypeLiteral
|
|
123
|
+
* property's type annotation).
|
|
124
124
|
*
|
|
125
125
|
* `scope` (when supplied) is the node the alias lookup walks outward from, which
|
|
126
126
|
* enables resolving a locally-declared named type alias to its definition, so
|
|
@@ -185,6 +185,46 @@ function typeNodeComposesWithProps(typeNode, propsTypeName, scope, seenAliases =
|
|
|
185
185
|
// case, where every arm composes with the single shared child.
|
|
186
186
|
return typeNode.types.some((t) => typeNodeComposesWithProps(t, propsTypeName, scope, seenAliases));
|
|
187
187
|
}
|
|
188
|
+
case utils_1.AST_NODE_TYPES.TSArrayType: {
|
|
189
|
+
// A list renderer's composition lives in the ELEMENT type: a parent
|
|
190
|
+
// declaring `buttons: readonly ActionButtonProps[]` and spreading one
|
|
191
|
+
// element onto each child forwards the child's ENTIRE prop object, which
|
|
192
|
+
// is the same DRY guarantee a direct `Pick`/`Omit` prop gives — the
|
|
193
|
+
// composition is simply one level of indirection away, inside the array.
|
|
194
|
+
// The child's contract belongs to the element type there, so demanding a
|
|
195
|
+
// whole-props Pick/Omit on the parent would name a composition a list
|
|
196
|
+
// renderer must not have (issue #2038). This is the array analogue of the
|
|
197
|
+
// union-arm unwrapping issue #1343 established.
|
|
198
|
+
return typeNodeComposesWithProps(typeNode.elementType, propsTypeName, scope, seenAliases);
|
|
199
|
+
}
|
|
200
|
+
case utils_1.AST_NODE_TYPES.TSTupleType: {
|
|
201
|
+
// A tuple is a fixed-length list, and each slot is handed to a child
|
|
202
|
+
// exactly as an array element is, so any slot that composes composes.
|
|
203
|
+
return typeNode.elementTypes.some((element) => typeNodeComposesWithProps(element, propsTypeName, scope, seenAliases));
|
|
204
|
+
}
|
|
205
|
+
case utils_1.AST_NODE_TYPES.TSNamedTupleMember: {
|
|
206
|
+
// A tuple slot's label names the slot, never its surface.
|
|
207
|
+
return typeNodeComposesWithProps(typeNode.elementType, propsTypeName, scope, seenAliases);
|
|
208
|
+
}
|
|
209
|
+
case utils_1.AST_NODE_TYPES.TSOptionalType:
|
|
210
|
+
case utils_1.AST_NODE_TYPES.TSRestType: {
|
|
211
|
+
// `?` and `...` govern how many slots a tuple carries, not what a slot
|
|
212
|
+
// carries, so the decorated type is the surface to test.
|
|
213
|
+
return typeNodeComposesWithProps(typeNode.typeAnnotation, propsTypeName, scope, seenAliases);
|
|
214
|
+
}
|
|
215
|
+
case utils_1.AST_NODE_TYPES.TSTypeOperator: {
|
|
216
|
+
// `readonly T[]` describes the same prop surface as `T[]`: the modifier
|
|
217
|
+
// constrains mutation of the container, never the shape of its elements.
|
|
218
|
+
//
|
|
219
|
+
// Only `readonly` unwraps. `keyof ChildProps` is the child's KEY union — a
|
|
220
|
+
// set of strings that hands the child nothing — and `unique symbol` is a
|
|
221
|
+
// nominal token, so crediting either would let a parent that merely names
|
|
222
|
+
// the child's keys pass as composing with its props.
|
|
223
|
+
if (typeNode.operator !== 'readonly' || !typeNode.typeAnnotation) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
return typeNodeComposesWithProps(typeNode.typeAnnotation, propsTypeName, scope, seenAliases);
|
|
227
|
+
}
|
|
188
228
|
case utils_1.AST_NODE_TYPES.TSTypeLiteral: {
|
|
189
229
|
// Check property signatures for nested composition
|
|
190
230
|
// e.g. { iconProps?: Omit<GradientIconButtonProps, 'IconComponent'> }
|
package/package.json
CHANGED
package/release-manifest.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "1.20.167",
|
|
4
|
+
"date": "2026-08-18T04:28:02.499Z",
|
|
5
|
+
"rules": [
|
|
6
|
+
{
|
|
7
|
+
"name": "require-props-composition",
|
|
8
|
+
"changeType": "fix",
|
|
9
|
+
"issues": [
|
|
10
|
+
2038
|
|
11
|
+
],
|
|
12
|
+
"summary": "credit composition through an array element (closes #2038)"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
2
16
|
{
|
|
3
17
|
"version": "1.20.166",
|
|
4
18
|
"date": "2026-08-18T03:18:38.188Z",
|