@@ -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 ,
@@ -220,16 +224,30 @@ const stringConstructorNewObjectReturningMethods = ["split"];
220
224
*/
221
225
function checkAssignmentExpression (
222
226
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 ;
227
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
228
+ rawOptions : Readonly < RawOptions > ,
229
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
230
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
231
+ const rootNode = findRootIdentifier ( node . left ) ?? node . left ;
232
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
233
+ rootNode ,
234
+ context ,
235
+ options ,
236
+ ) ;
237
+
238
+ if ( optionsToUse === null ) {
239
+ return {
240
+ context,
241
+ descriptors : [ ] ,
242
+ } ;
243
+ }
244
+
227
245
const {
228
246
ignoreIdentifierPattern,
229
247
ignoreAccessorPattern,
230
248
ignoreNonConstDeclarations,
231
249
ignoreClasses,
232
- } = optionsObject ;
250
+ } = optionsToUse ;
233
251
234
252
if (
235
253
! isMemberExpression ( node . left ) ||
@@ -285,16 +303,30 @@ function checkAssignmentExpression(
285
303
*/
286
304
function checkUnaryExpression (
287
305
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 ;
306
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
307
+ rawOptions : Readonly < RawOptions > ,
308
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
309
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
310
+ const rootNode = findRootIdentifier ( node . argument ) ?? node . argument ;
311
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
312
+ rootNode ,
313
+ context ,
314
+ options ,
315
+ ) ;
316
+
317
+ if ( optionsToUse === null ) {
318
+ return {
319
+ context,
320
+ descriptors : [ ] ,
321
+ } ;
322
+ }
323
+
292
324
const {
293
325
ignoreIdentifierPattern,
294
326
ignoreAccessorPattern,
295
327
ignoreNonConstDeclarations,
296
328
ignoreClasses,
297
- } = optionsObject ;
329
+ } = optionsToUse ;
298
330
299
331
if (
300
332
! isMemberExpression ( node . argument ) ||
@@ -349,16 +381,30 @@ function checkUnaryExpression(
349
381
*/
350
382
function checkUpdateExpression (
351
383
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 ;
384
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
385
+ rawOptions : Readonly < RawOptions > ,
386
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
387
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
388
+ const rootNode = findRootIdentifier ( node . argument ) ?? node . argument ;
389
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
390
+ rootNode ,
391
+ context ,
392
+ options ,
393
+ ) ;
394
+
395
+ if ( optionsToUse === null ) {
396
+ return {
397
+ context,
398
+ descriptors : [ ] ,
399
+ } ;
400
+ }
401
+
356
402
const {
357
403
ignoreIdentifierPattern,
358
404
ignoreAccessorPattern,
359
405
ignoreNonConstDeclarations,
360
406
ignoreClasses,
361
- } = optionsObject ;
407
+ } = optionsToUse ;
362
408
363
409
if (
364
410
! isMemberExpression ( node . argument ) ||
@@ -416,7 +462,7 @@ function checkUpdateExpression(
416
462
*/
417
463
function isInChainCallAndFollowsNew (
418
464
node : TSESTree . Expression ,
419
- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
465
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
420
466
) : boolean {
421
467
if ( isMemberExpression ( node ) ) {
422
468
return isInChainCallAndFollowsNew ( node . object , context ) ;
@@ -488,16 +534,30 @@ function isInChainCallAndFollowsNew(
488
534
*/
489
535
function checkCallExpression (
490
536
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 ;
537
+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
538
+ rawOptions : Readonly < RawOptions > ,
539
+ ) : RuleResult < keyof typeof errorMessages , RawOptions > {
540
+ const options = upgradeRawOverridableOptions ( rawOptions [ 0 ] ) ;
541
+ const rootNode = findRootIdentifier ( node . callee ) ?? node . callee ;
542
+ const optionsToUse = getCoreOptions < CoreOptions , Options > (
543
+ rootNode ,
544
+ context ,
545
+ options ,
546
+ ) ;
547
+
548
+ if ( optionsToUse === null ) {
549
+ return {
550
+ context,
551
+ descriptors : [ ] ,
552
+ } ;
553
+ }
554
+
495
555
const {
496
556
ignoreIdentifierPattern,
497
557
ignoreAccessorPattern,
498
558
ignoreNonConstDeclarations,
499
559
ignoreClasses,
500
- } = optionsObject ;
560
+ } = optionsToUse ;
501
561
502
562
// Not potential object mutation?
503
563
if (
@@ -517,7 +577,7 @@ function checkCallExpression(
517
577
} ;
518
578
}
519
579
520
- const { ignoreImmediateMutation } = optionsObject ;
580
+ const { ignoreImmediateMutation } = optionsToUse ;
521
581
522
582
// Array mutation?
523
583
if (
@@ -608,7 +668,7 @@ function checkCallExpression(
608
668
}
609
669
610
670
// Create the rule.
611
- export const rule = createRule < keyof typeof errorMessages , Options > (
671
+ export const rule = createRule < keyof typeof errorMessages , RawOptions > (
612
672
name ,
613
673
meta ,
614
674
defaultOptions ,
0 commit comments