@@ -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 "#eslint-plugin-functional/options" ;
19
23
import {
20
24
isExpected ,
@@ -26,6 +30,7 @@ import {
26
30
createRule ,
27
31
getTypeOfNode ,
28
32
} from "#eslint-plugin-functional/utils/rule" ;
33
+ import { overridableOptionsSchema } from "#eslint-plugin-functional/utils/schemas" ;
29
34
import {
30
35
findRootIdentifier ,
31
36
isDefinedByMutableVariable ,
@@ -53,62 +58,61 @@ export const name = "immutable-data";
53
58
*/
54
59
export const fullName = `${ ruleNameScope } /${ name } ` ;
55
60
61
+ type CoreOptions = IgnoreAccessorPatternOption &
62
+ IgnoreClassesOption &
63
+ IgnoreIdentifierPatternOption & {
64
+ ignoreImmediateMutation : boolean ;
65
+ ignoreNonConstDeclarations :
66
+ | boolean
67
+ | {
68
+ treatParametersAsConst : boolean ;
69
+ } ;
70
+ } ;
71
+
56
72
/**
57
73
* The options this rule can take.
58
74
*/
59
- type Options = [
60
- IgnoreAccessorPatternOption &
61
- IgnoreClassesOption &
62
- IgnoreIdentifierPatternOption & {
63
- ignoreImmediateMutation : boolean ;
64
- ignoreNonConstDeclarations :
65
- | boolean
66
- | {
67
- treatParametersAsConst : boolean ;
68
- } ;
69
- } ,
70
- ] ;
75
+ type RawOptions = [ RawOverridableOptions < CoreOptions > ] ;
76
+ type Options = OverridableOptions < CoreOptions > ;
71
77
72
- /**
73
- * The schema for the rule options.
74
- */
75
- const schema : JSONSchema4 [ ] = [
78
+ const coreOptionsPropertiesSchema = deepmerge (
79
+ ignoreIdentifierPatternOptionSchema ,
80
+ ignoreAccessorPatternOptionSchema ,
81
+ ignoreClassesOptionSchema ,
76
82
{
77
- type : "object" ,
78
- properties : deepmerge (
79
- ignoreIdentifierPatternOptionSchema ,
80
- ignoreAccessorPatternOptionSchema ,
81
- ignoreClassesOptionSchema ,
82
- {
83
- ignoreImmediateMutation : {
83
+ ignoreImmediateMutation : {
84
+ type : "boolean" ,
85
+ } ,
86
+ ignoreNonConstDeclarations : {
87
+ oneOf : [
88
+ {
84
89
type : "boolean" ,
85
90
} ,
86
- ignoreNonConstDeclarations : {
87
- oneOf : [
88
- {
91
+ {
92
+ type : "object" ,
93
+ properties : {
94
+ treatParametersAsConst : {
89
95
type : "boolean" ,
90
96
} ,
91
- {
92
- type : "object" ,
93
- properties : {
94
- treatParametersAsConst : {
95
- type : "boolean" ,
96
- } ,
97
- } ,
98
- additionalProperties : false ,
99
- } ,
100
- ] ,
97
+ } ,
98
+ additionalProperties : false ,
101
99
} ,
102
- } satisfies JSONSchema4ObjectSchema [ "properties" ] ,
103
- ) ,
104
- additionalProperties : false ,
100
+ ] ,
101
+ } ,
105
102
} ,
103
+ ) as NonNullable < JSONSchema4ObjectSchema [ "properties" ] > ;
104
+
105
+ /**
106
+ * The schema for the rule options.
107
+ */
108
+ const schema : JSONSchema4 [ ] = [
109
+ overridableOptionsSchema ( coreOptionsPropertiesSchema ) ,
106
110
] ;
107
111
108
112
/**
109
113
* The default options for the rule.
110
114
*/
111
- const defaultOptions : Options = [
115
+ const defaultOptions : RawOptions = [
112
116
{
113
117
ignoreClasses : false ,
114
118
ignoreImmediateMutation : true ,
@@ -128,18 +132,19 @@ const errorMessages = {
128
132
/**
129
133
* The meta data for this rule.
130
134
*/
131
- const meta : NamedCreateRuleCustomMeta < keyof typeof errorMessages , Options > = {
132
- type : "suggestion" ,
133
- docs : {
134
- category : "No Mutations" ,
135
- description : "Enforce treating data as immutable." ,
136
- recommended : "recommended" ,
137
- recommendedSeverity : "error" ,
138
- requiresTypeChecking : true ,
139
- } ,
140
- messages : errorMessages ,
141
- schema,
142
- } ;
135
+ const meta : NamedCreateRuleCustomMeta < keyof typeof errorMessages , RawOptions > =
136
+ {
137
+ type : "suggestion" ,
138
+ docs : {
139
+ category : "No Mutations" ,
140
+ description : "Enforce treating data as immutable." ,
141
+ recommended : "recommended" ,
142
+ recommendedSeverity : "error" ,
143
+ requiresTypeChecking : true ,
144
+ } ,
145
+ messages : errorMessages ,
146
+ schema,
147
+ } ;
143
148
144
149
/**
145
150
* Array methods that mutate an array.
@@ -220,16 +225,30 @@ const stringConstructorNewObjectReturningMethods = ["split"];
220
225
*/
221
226
function checkAssignmentExpression (
222
227
node : TSESTree . AssignmentExpression ,
223
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
224
- options : Readonly < Options > ,
225
- ) : RuleResult < keyof typeof errorMessages , Options > {
226
- const [ optionsObject ] = options ;
228
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
229
+ rawOptions : Readonly < RawOptions > ,
230
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
231
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
232
+ const rootNode = findRootIdentifier ( node . left ) ?? node . left ;
233
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
234
+ rootNode ,
235
+ context ,
236
+ options ,
237
+ ) ;
238
+
239
+ if ( optionsToUse === null ) {
240
+ return {
241
+ context,
242
+ descriptors : [ ] ,
243
+ } ;
244
+ }
245
+
227
246
const {
228
247
ignoreIdentifierPattern,
229
248
ignoreAccessorPattern,
230
249
ignoreNonConstDeclarations,
231
250
ignoreClasses,
232
- } = optionsObject ;
251
+ } = optionsToUse ;
233
252
234
253
if (
235
254
! isMemberExpression ( node . left ) ||
@@ -285,16 +304,30 @@ function checkAssignmentExpression(
285
304
*/
286
305
function checkUnaryExpression (
287
306
node : TSESTree . UnaryExpression ,
288
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
289
- options : Readonly < Options > ,
290
- ) : RuleResult < keyof typeof errorMessages , Options > {
291
- const [ optionsObject ] = options ;
307
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
308
+ rawOptions : Readonly < RawOptions > ,
309
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
310
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
311
+ const rootNode = findRootIdentifier ( node . argument ) ?? node . argument ;
312
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
313
+ rootNode ,
314
+ context ,
315
+ options ,
316
+ ) ;
317
+
318
+ if ( optionsToUse === null ) {
319
+ return {
320
+ context,
321
+ descriptors : [ ] ,
322
+ } ;
323
+ }
324
+
292
325
const {
293
326
ignoreIdentifierPattern,
294
327
ignoreAccessorPattern,
295
328
ignoreNonConstDeclarations,
296
329
ignoreClasses,
297
- } = optionsObject ;
330
+ } = optionsToUse ;
298
331
299
332
if (
300
333
! isMemberExpression ( node . argument ) ||
@@ -349,16 +382,30 @@ function checkUnaryExpression(
349
382
*/
350
383
function checkUpdateExpression (
351
384
node : TSESTree . UpdateExpression ,
352
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
353
- options : Readonly < Options > ,
354
- ) : RuleResult < keyof typeof errorMessages , Options > {
355
- const [ optionsObject ] = options ;
385
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
386
+ rawOptions : Readonly < RawOptions > ,
387
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
388
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
389
+ const rootNode = findRootIdentifier ( node . argument ) ?? node . argument ;
390
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
391
+ rootNode ,
392
+ context ,
393
+ options ,
394
+ ) ;
395
+
396
+ if ( optionsToUse === null ) {
397
+ return {
398
+ context,
399
+ descriptors : [ ] ,
400
+ } ;
401
+ }
402
+
356
403
const {
357
404
ignoreIdentifierPattern,
358
405
ignoreAccessorPattern,
359
406
ignoreNonConstDeclarations,
360
407
ignoreClasses,
361
- } = optionsObject ;
408
+ } = optionsToUse ;
362
409
363
410
if (
364
411
! isMemberExpression ( node . argument ) ||
@@ -416,7 +463,7 @@ function checkUpdateExpression(
416
463
*/
417
464
function isInChainCallAndFollowsNew (
418
465
node : TSESTree . Expression ,
419
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
466
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
420
467
) : boolean {
421
468
if ( isMemberExpression ( node ) ) {
422
469
return isInChainCallAndFollowsNew ( node . object , context ) ;
@@ -488,16 +535,30 @@ function isInChainCallAndFollowsNew(
488
535
*/
489
536
function checkCallExpression (
490
537
node : TSESTree . CallExpression ,
491
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
492
- options : Readonly < Options > ,
493
- ) : RuleResult < keyof typeof errorMessages , Options > {
494
- const [ optionsObject ] = options ;
538
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
539
+ rawOptions : Readonly < RawOptions > ,
540
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
541
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
542
+ const rootNode = findRootIdentifier ( node . callee ) ?? node . callee ;
543
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
544
+ rootNode ,
545
+ context ,
546
+ options ,
547
+ ) ;
548
+
549
+ if ( optionsToUse === null ) {
550
+ return {
551
+ context,
552
+ descriptors : [ ] ,
553
+ } ;
554
+ }
555
+
495
556
const {
496
557
ignoreIdentifierPattern,
497
558
ignoreAccessorPattern,
498
559
ignoreNonConstDeclarations,
499
560
ignoreClasses,
500
- } = optionsObject ;
561
+ } = optionsToUse ;
501
562
502
563
// Not potential object mutation?
503
564
if (
@@ -517,7 +578,7 @@ function checkCallExpression(
517
578
} ;
518
579
}
519
580
520
- const { ignoreImmediateMutation } = optionsObject ;
581
+ const { ignoreImmediateMutation } = optionsToUse ;
521
582
522
583
// Array mutation?
523
584
if (
@@ -608,7 +669,7 @@ function checkCallExpression(
608
669
}
609
670
610
671
// Create the rule.
611
- export const rule = createRule < keyof typeof errorMessages , Options > (
672
+ export const rule = createRule < keyof typeof errorMessages , RawOptions > (
612
673
name ,
613
674
meta ,
614
675
defaultOptions ,
0 commit comments