@@ -10,11 +10,15 @@ import {
1010 type IgnoreAccessorPatternOption ,
1111 type IgnoreClassesOption ,
1212 type IgnoreIdentifierPatternOption ,
13+ type OverridableOptions ,
14+ type RawOverridableOptions ,
15+ getCoreOptions ,
1316 ignoreAccessorPatternOptionSchema ,
1417 ignoreClassesOptionSchema ,
1518 ignoreIdentifierPatternOptionSchema ,
1619 shouldIgnoreClasses ,
1720 shouldIgnorePattern ,
21+ upgradeRawOverridableOptions ,
1822} from "#/options" ;
1923import { isExpected , ruleNameScope } from "#/utils/misc" ;
2024import {
@@ -24,6 +28,7 @@ import {
2428 createRule ,
2529 getTypeOfNode ,
2630} from "#/utils/rule" ;
31+ import { overridableOptionsSchema } from "#/utils/schemas" ;
2732import {
2833 findRootIdentifier ,
2934 isDefinedByMutableVariable ,
@@ -51,62 +56,61 @@ export const name = "immutable-data";
5156 */
5257export const fullName : `${typeof ruleNameScope } /${typeof name } ` = `${ ruleNameScope } /${ name } ` ;
5358
59+ type CoreOptions = IgnoreAccessorPatternOption &
60+ IgnoreClassesOption &
61+ IgnoreIdentifierPatternOption & {
62+ ignoreImmediateMutation : boolean ;
63+ ignoreNonConstDeclarations :
64+ | boolean
65+ | {
66+ treatParametersAsConst : boolean ;
67+ } ;
68+ } ;
69+
5470/**
5571 * The options this rule can take.
5672 */
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 > ;
6975
70- /**
71- * The schema for the rule options.
72- */
73- const schema : JSONSchema4 [ ] = [
76+ const coreOptionsPropertiesSchema = deepmerge (
77+ ignoreIdentifierPatternOptionSchema ,
78+ ignoreAccessorPatternOptionSchema ,
79+ ignoreClassesOptionSchema ,
7480 {
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+ {
8287 type : "boolean" ,
8388 } ,
84- ignoreNonConstDeclarations : {
85- oneOf : [
86- {
89+ {
90+ type : "object" ,
91+ properties : {
92+ treatParametersAsConst : {
8793 type : "boolean" ,
8894 } ,
89- {
90- type : "object" ,
91- properties : {
92- treatParametersAsConst : {
93- type : "boolean" ,
94- } ,
95- } ,
96- additionalProperties : false ,
97- } ,
98- ] ,
95+ } ,
96+ additionalProperties : false ,
9997 } ,
100- } satisfies JSONSchema4ObjectSchema [ "properties" ] ,
101- ) ,
102- additionalProperties : false ,
98+ ] ,
99+ } ,
103100 } ,
101+ ) as NonNullable < JSONSchema4ObjectSchema [ "properties" ] > ;
102+
103+ /**
104+ * The schema for the rule options.
105+ */
106+ const schema : JSONSchema4 [ ] = [
107+ overridableOptionsSchema ( coreOptionsPropertiesSchema ) ,
104108] ;
105109
106110/**
107111 * The default options for the rule.
108112 */
109- const defaultOptions : Options = [
113+ const defaultOptions : RawOptions = [
110114 {
111115 ignoreClasses : false ,
112116 ignoreImmediateMutation : true ,
@@ -218,16 +222,30 @@ const stringConstructorNewObjectReturningMethods = ["split"];
218222 */
219223function checkAssignmentExpression (
220224 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+
225243 const {
226244 ignoreIdentifierPattern,
227245 ignoreAccessorPattern,
228246 ignoreNonConstDeclarations,
229247 ignoreClasses,
230- } = optionsObject ;
248+ } = optionsToUse ;
231249
232250 if (
233251 ! isMemberExpression ( node . left ) ||
@@ -283,16 +301,30 @@ function checkAssignmentExpression(
283301 */
284302function checkUnaryExpression (
285303 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+
290322 const {
291323 ignoreIdentifierPattern,
292324 ignoreAccessorPattern,
293325 ignoreNonConstDeclarations,
294326 ignoreClasses,
295- } = optionsObject ;
327+ } = optionsToUse ;
296328
297329 if (
298330 ! isMemberExpression ( node . argument ) ||
@@ -347,16 +379,30 @@ function checkUnaryExpression(
347379 */
348380function checkUpdateExpression (
349381 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+
354400 const {
355401 ignoreIdentifierPattern,
356402 ignoreAccessorPattern,
357403 ignoreNonConstDeclarations,
358404 ignoreClasses,
359- } = optionsObject ;
405+ } = optionsToUse ;
360406
361407 if (
362408 ! isMemberExpression ( node . argument ) ||
@@ -414,7 +460,7 @@ function checkUpdateExpression(
414460 */
415461function isInChainCallAndFollowsNew (
416462 node : TSESTree . Expression ,
417- context : Readonly < RuleContext < keyof typeof errorMessages , Options > > ,
463+ context : Readonly < RuleContext < keyof typeof errorMessages , RawOptions > > ,
418464) : boolean {
419465 if ( isMemberExpression ( node ) ) {
420466 return isInChainCallAndFollowsNew ( node . object , context ) ;
@@ -486,16 +532,30 @@ function isInChainCallAndFollowsNew(
486532 */
487533function checkCallExpression (
488534 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+
493553 const {
494554 ignoreIdentifierPattern,
495555 ignoreAccessorPattern,
496556 ignoreNonConstDeclarations,
497557 ignoreClasses,
498- } = optionsObject ;
558+ } = optionsToUse ;
499559
500560 // Not potential object mutation?
501561 if (
@@ -515,7 +575,7 @@ function checkCallExpression(
515575 } ;
516576 }
517577
518- const { ignoreImmediateMutation } = optionsObject ;
578+ const { ignoreImmediateMutation } = optionsToUse ;
519579
520580 // Array mutation?
521581 if (
@@ -606,9 +666,9 @@ function checkCallExpression(
606666}
607667
608668// Create the rule.
609- export const rule : Rule < keyof typeof errorMessages , Options > = createRule <
669+ export const rule : Rule < keyof typeof errorMessages , RawOptions > = createRule <
610670 keyof typeof errorMessages ,
611- Options
671+ RawOptions
612672> ( name , meta , defaultOptions , {
613673 AssignmentExpression : checkAssignmentExpression ,
614674 UnaryExpression : checkUnaryExpression ,
0 commit comments