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