@@ -10,11 +10,15 @@ import {
10
10
type IgnoreAccessorPatternOption ,
11
11
type IgnoreClassesOption ,
12
12
type IgnoreIdentifierPatternOption ,
13
+ type OverridableOptions ,
14
+ type RawOverridableOptions ,
15
+ getCoreOptions ,
13
16
ignoreAccessorPatternOptionSchema ,
14
17
ignoreClassesOptionSchema ,
15
18
ignoreIdentifierPatternOptionSchema ,
16
19
shouldIgnoreClasses ,
17
20
shouldIgnorePattern ,
21
+ upgradeRawOverridableOptions ,
18
22
} from "#/options" ;
19
23
import { isExpected , ruleNameScope } from "#/utils/misc" ;
20
24
import {
@@ -23,6 +27,7 @@ import {
23
27
createRule ,
24
28
getTypeOfNode ,
25
29
} from "#/utils/rule" ;
30
+ import { overridableOptionsSchema } from "#/utils/schemas" ;
26
31
import {
27
32
findRootIdentifier ,
28
33
isDefinedByMutableVariable ,
@@ -50,62 +55,61 @@ export const name = "immutable-data";
50
55
*/
51
56
export const fullName = `${ ruleNameScope } /${ name } ` ;
52
57
58
+ type CoreOptions = IgnoreAccessorPatternOption &
59
+ IgnoreClassesOption &
60
+ IgnoreIdentifierPatternOption & {
61
+ ignoreImmediateMutation : boolean ;
62
+ ignoreNonConstDeclarations :
63
+ | boolean
64
+ | {
65
+ treatParametersAsConst : boolean ;
66
+ } ;
67
+ } ;
68
+
53
69
/**
54
70
* The options this rule can take.
55
71
*/
56
- type Options = [
57
- IgnoreAccessorPatternOption &
58
- IgnoreClassesOption &
59
- IgnoreIdentifierPatternOption & {
60
- ignoreImmediateMutation : boolean ;
61
- ignoreNonConstDeclarations :
62
- | boolean
63
- | {
64
- treatParametersAsConst : boolean ;
65
- } ;
66
- } ,
67
- ] ;
72
+ type RawOptions = [ RawOverridableOptions < CoreOptions > ] ;
73
+ type Options = OverridableOptions < CoreOptions > ;
68
74
69
- /**
70
- * The schema for the rule options.
71
- */
72
- const schema : JSONSchema4 [ ] = [
75
+ const coreOptionsPropertiesSchema = deepmerge (
76
+ ignoreIdentifierPatternOptionSchema ,
77
+ ignoreAccessorPatternOptionSchema ,
78
+ ignoreClassesOptionSchema ,
73
79
{
74
- type : "object" ,
75
- properties : deepmerge (
76
- ignoreIdentifierPatternOptionSchema ,
77
- ignoreAccessorPatternOptionSchema ,
78
- ignoreClassesOptionSchema ,
79
- {
80
- ignoreImmediateMutation : {
80
+ ignoreImmediateMutation : {
81
+ type : "boolean" ,
82
+ } ,
83
+ ignoreNonConstDeclarations : {
84
+ oneOf : [
85
+ {
81
86
type : "boolean" ,
82
87
} ,
83
- ignoreNonConstDeclarations : {
84
- oneOf : [
85
- {
88
+ {
89
+ type : "object" ,
90
+ properties : {
91
+ treatParametersAsConst : {
86
92
type : "boolean" ,
87
93
} ,
88
- {
89
- type : "object" ,
90
- properties : {
91
- treatParametersAsConst : {
92
- type : "boolean" ,
93
- } ,
94
- } ,
95
- additionalProperties : false ,
96
- } ,
97
- ] ,
94
+ } ,
95
+ additionalProperties : false ,
98
96
} ,
99
- } satisfies JSONSchema4ObjectSchema [ "properties" ] ,
100
- ) ,
101
- additionalProperties : false ,
97
+ ] ,
98
+ } ,
102
99
} ,
100
+ ) as NonNullable < JSONSchema4ObjectSchema [ "properties" ] > ;
101
+
102
+ /**
103
+ * The schema for the rule options.
104
+ */
105
+ const schema : JSONSchema4 [ ] = [
106
+ overridableOptionsSchema ( coreOptionsPropertiesSchema ) ,
103
107
] ;
104
108
105
109
/**
106
110
* The default options for the rule.
107
111
*/
108
- const defaultOptions : Options = [
112
+ const defaultOptions : RawOptions = [
109
113
{
110
114
ignoreClasses : false ,
111
115
ignoreImmediateMutation : true ,
@@ -217,16 +221,30 @@ const stringConstructorNewObjectReturningMethods = ["split"];
217
221
*/
218
222
function checkAssignmentExpression (
219
223
node : TSESTree . AssignmentExpression ,
220
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
221
- options : Readonly < Options > ,
222
- ) : RuleResult < keyof typeof errorMessages , Options > {
223
- const [ optionsObject ] = options ;
224
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
225
+ rawOptions : Readonly < RawOptions > ,
226
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
227
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
228
+ const rootNode = findRootIdentifier ( node . left ) ?? node . left ;
229
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
230
+ rootNode ,
231
+ context ,
232
+ options ,
233
+ ) ;
234
+
235
+ if ( optionsToUse === null ) {
236
+ return {
237
+ context,
238
+ descriptors : [ ] ,
239
+ } ;
240
+ }
241
+
224
242
const {
225
243
ignoreIdentifierPattern,
226
244
ignoreAccessorPattern,
227
245
ignoreNonConstDeclarations,
228
246
ignoreClasses,
229
- } = optionsObject ;
247
+ } = optionsToUse ;
230
248
231
249
if (
232
250
! isMemberExpression ( node . left ) ||
@@ -282,16 +300,30 @@ function checkAssignmentExpression(
282
300
*/
283
301
function checkUnaryExpression (
284
302
node : TSESTree . UnaryExpression ,
285
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
286
- options : Readonly < Options > ,
287
- ) : RuleResult < keyof typeof errorMessages , Options > {
288
- const [ optionsObject ] = options ;
303
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
304
+ rawOptions : Readonly < RawOptions > ,
305
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
306
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
307
+ const rootNode = findRootIdentifier ( node . argument ) ?? node . argument ;
308
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
309
+ rootNode ,
310
+ context ,
311
+ options ,
312
+ ) ;
313
+
314
+ if ( optionsToUse === null ) {
315
+ return {
316
+ context,
317
+ descriptors : [ ] ,
318
+ } ;
319
+ }
320
+
289
321
const {
290
322
ignoreIdentifierPattern,
291
323
ignoreAccessorPattern,
292
324
ignoreNonConstDeclarations,
293
325
ignoreClasses,
294
- } = optionsObject ;
326
+ } = optionsToUse ;
295
327
296
328
if (
297
329
! isMemberExpression ( node . argument ) ||
@@ -346,16 +378,30 @@ function checkUnaryExpression(
346
378
*/
347
379
function checkUpdateExpression (
348
380
node : TSESTree . UpdateExpression ,
349
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
350
- options : Readonly < Options > ,
351
- ) : RuleResult < keyof typeof errorMessages , Options > {
352
- const [ optionsObject ] = options ;
381
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
382
+ rawOptions : Readonly < RawOptions > ,
383
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
384
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
385
+ const rootNode = findRootIdentifier ( node . argument ) ?? node . argument ;
386
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
387
+ rootNode ,
388
+ context ,
389
+ options ,
390
+ ) ;
391
+
392
+ if ( optionsToUse === null ) {
393
+ return {
394
+ context,
395
+ descriptors : [ ] ,
396
+ } ;
397
+ }
398
+
353
399
const {
354
400
ignoreIdentifierPattern,
355
401
ignoreAccessorPattern,
356
402
ignoreNonConstDeclarations,
357
403
ignoreClasses,
358
- } = optionsObject ;
404
+ } = optionsToUse ;
359
405
360
406
if (
361
407
! isMemberExpression ( node . argument ) ||
@@ -413,7 +459,7 @@ function checkUpdateExpression(
413
459
*/
414
460
function isInChainCallAndFollowsNew (
415
461
node : TSESTree . Expression ,
416
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
462
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
417
463
) : boolean {
418
464
if ( isMemberExpression ( node ) ) {
419
465
return isInChainCallAndFollowsNew ( node . object , context ) ;
@@ -485,16 +531,30 @@ function isInChainCallAndFollowsNew(
485
531
*/
486
532
function checkCallExpression (
487
533
node : TSESTree . CallExpression ,
488
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
489
- options : Readonly < Options > ,
490
- ) : RuleResult < keyof typeof errorMessages , Options > {
491
- const [ optionsObject ] = options ;
534
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
535
+ rawOptions : Readonly < RawOptions > ,
536
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
537
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
538
+ const rootNode = findRootIdentifier ( node . callee ) ?? node . callee ;
539
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
540
+ rootNode ,
541
+ context ,
542
+ options ,
543
+ ) ;
544
+
545
+ if ( optionsToUse === null ) {
546
+ return {
547
+ context,
548
+ descriptors : [ ] ,
549
+ } ;
550
+ }
551
+
492
552
const {
493
553
ignoreIdentifierPattern,
494
554
ignoreAccessorPattern,
495
555
ignoreNonConstDeclarations,
496
556
ignoreClasses,
497
- } = optionsObject ;
557
+ } = optionsToUse ;
498
558
499
559
// Not potential object mutation?
500
560
if (
@@ -514,7 +574,7 @@ function checkCallExpression(
514
574
} ;
515
575
}
516
576
517
- const { ignoreImmediateMutation } = optionsObject ;
577
+ const { ignoreImmediateMutation } = optionsToUse ;
518
578
519
579
// Array mutation?
520
580
if (
@@ -605,7 +665,7 @@ function checkCallExpression(
605
665
}
606
666
607
667
// Create the rule.
608
- export const rule = createRule < keyof typeof errorMessages , Options > (
668
+ export const rule = createRule < keyof typeof errorMessages , RawOptions > (
609
669
name ,
610
670
meta ,
611
671
defaultOptions ,
0 commit comments