77
88const { flatConfigSchema} = require ( "../../../lib/config/flat-config-schema" ) ;
99const { assert} = require ( "chai" ) ;
10+ const { Legacy :{ ConfigArray} } = require ( "@eslint/eslintrc" ) ;
11+
12+ /**
13+ * This function checks the result of merging two values in eslintrc config.
14+ * It uses deep strict equality to compare the actual and the expected results.
15+ * This is useful to ensure that the flat config merge logic behaves similarly to the old logic.
16+ * When eslintrc is removed, this function and its invocations can be also removed.
17+ *@param {Object } [first] The base object.
18+ *@param {Object } [second] The overrides object.
19+ *@param {Object } [expectedResult] The expected reults of merging first and second values.
20+ *@returns {void }
21+ */
22+ function confirmLegacyMergeResult ( first , second , expectedResult ) {
23+ const configArray = new ConfigArray (
24+ { settings :first } ,
25+ { settings :second }
26+ ) ;
27+ const config = configArray . extractConfig ( "/file" ) ;
28+ const actualResult = config . settings ;
29+
30+ assert . deepStrictEqual ( actualResult , expectedResult ) ;
31+ }
1032
1133describe ( "merge" , ( ) => {
1234
@@ -18,36 +40,14 @@ describe("merge", () => {
1840const result = merge ( first , second ) ;
1941
2042assert . deepStrictEqual ( result , { ...first , ...second } ) ;
21- } ) ;
22-
23- it ( "overrides an object with an array" , ( ) => {
24- const first = { foo :42 } ;
25- const second = [ "bar" , "baz" ] ;
26- const result = merge ( first , second ) ;
27-
28- assert . strictEqual ( result , second ) ;
29- } ) ;
30-
31- it ( "merges an array with an object" , ( ) => {
32- const first = [ "foo" , "bar" ] ;
33- const second = { baz :42 } ;
34- const result = merge ( first , second ) ;
35-
36- assert . deepStrictEqual ( result , { 0 :"foo" , 1 :"bar" , baz :42 } ) ;
37- } ) ;
38-
39- it ( "overrides an array with another array" , ( ) => {
40- const first = [ "foo" , "bar" ] ;
41- const second = [ "baz" , "qux" ] ;
42- const result = merge ( first , second ) ;
43-
44- assert . strictEqual ( result , second ) ;
43+ confirmLegacyMergeResult ( first , second , result ) ;
4544} ) ;
4645
4746it ( "returns an emtpy object if both values are undefined" , ( ) => {
4847const result = merge ( void 0 , void 0 ) ;
4948
5049assert . deepStrictEqual ( result , { } ) ;
50+ confirmLegacyMergeResult ( void 0 , void 0 , result ) ;
5151} ) ;
5252
5353it ( "returns an object equal to the first one if the second one is undefined" , ( ) => {
@@ -56,6 +56,7 @@ describe("merge", () => {
5656
5757assert . deepStrictEqual ( result , first ) ;
5858assert . notStrictEqual ( result , first ) ;
59+ confirmLegacyMergeResult ( first , void 0 , result ) ;
5960} ) ;
6061
6162it ( "returns an object equal to the second one if the first one is undefined" , ( ) => {
@@ -64,6 +65,16 @@ describe("merge", () => {
6465
6566assert . deepStrictEqual ( result , second ) ;
6667assert . notStrictEqual ( result , second ) ;
68+ confirmLegacyMergeResult ( void 0 , second , result ) ;
69+ } ) ;
70+
71+ it ( "does not preserve the type of merged objects" , ( ) => {
72+ const first = new Set ( [ "foo" , "bar" ] ) ;
73+ const second = new Set ( [ "baz" ] ) ;
74+ const result = merge ( first , second ) ;
75+
76+ assert . deepStrictEqual ( result , { } ) ;
77+ confirmLegacyMergeResult ( first , second , result ) ;
6778} ) ;
6879
6980it ( "merges two objects in a property" , ( ) => {
@@ -72,6 +83,34 @@ describe("merge", () => {
7283const result = merge ( first , second ) ;
7384
7485assert . deepStrictEqual ( result , { foo :{ bar :"baz" , qux :42 } } ) ;
86+ confirmLegacyMergeResult ( first , second , result ) ;
87+ } ) ;
88+
89+ it ( "overwrites an object in a property with an array" , ( ) => {
90+ const first = { someProperty :{ 1 :"foo" , bar :"baz" } } ;
91+ const second = { someProperty :[ "qux" ] } ;
92+ const result = merge ( first , second ) ;
93+
94+ assert . deepStrictEqual ( result , second ) ;
95+ assert . strictEqual ( result . someProperty , second . someProperty ) ;
96+ } ) ;
97+
98+ it ( "overwrites an array in a property with another array" , ( ) => {
99+ const first = { someProperty :[ "foo" , "bar" , void 0 , "baz" ] } ;
100+ const second = { someProperty :[ "qux" , void 0 , 42 ] } ;
101+ const result = merge ( first , second ) ;
102+
103+ assert . deepStrictEqual ( result , second ) ;
104+ assert . strictEqual ( result . someProperty , second . someProperty ) ;
105+ } ) ;
106+
107+ it ( "overwrites an array in a property with an object" , ( ) => {
108+ const first = { foo :[ "foobar" ] } ;
109+ const second = { foo :{ 1 :"qux" , bar :"baz" } } ;
110+ const result = merge ( first , second ) ;
111+
112+ assert . deepStrictEqual ( result , second ) ;
113+ assert . strictEqual ( result . foo , second . foo ) ;
75114} ) ;
76115
77116it ( "does not override a value in a property with undefined" , ( ) => {
@@ -81,6 +120,7 @@ describe("merge", () => {
81120
82121assert . deepStrictEqual ( result , first ) ;
83122assert . notStrictEqual ( result , first ) ;
123+ confirmLegacyMergeResult ( first , second , result ) ;
84124} ) ;
85125
86126it ( "does not change the prototype of a merged object" , ( ) => {
@@ -89,39 +129,104 @@ describe("merge", () => {
89129const result = merge ( first , second ) ;
90130
91131assert . strictEqual ( Object . getPrototypeOf ( result ) , Object . prototype ) ;
132+ confirmLegacyMergeResult ( first , second , result ) ;
92133} ) ;
93134
94135it ( "does not merge the '__proto__' property" , ( ) => {
95136const first = { [ "__proto__" ] :{ foo :42 } } ;
96137const second = { [ "__proto__" ] :{ bar :"baz" } } ;
97138const result = merge ( first , second ) ;
98139
99- assert . deepStrictEqual ( result , second ) ;
100- assert . notStrictEqual ( result , second ) ;
140+ assert . deepStrictEqual ( result , { } ) ;
141+ confirmLegacyMergeResult ( first , second , result ) ;
101142} ) ;
102143
103- it ( "throws an error if a value in a property is overriden with null" , ( ) => {
144+ it ( "overrides a value in a property with null" , ( ) => {
104145const first = { foo :{ bar :"baz" } } ;
105146const second = { foo :null } ;
147+ const result = merge ( first , second ) ;
106148
107- assert . throws ( ( ) => merge ( first , second ) , TypeError ) ;
149+ assert . deepStrictEqual ( result , second ) ;
150+ assert . notStrictEqual ( result , second ) ;
151+ confirmLegacyMergeResult ( first , second , result ) ;
108152} ) ;
109153
110- it ( "does not override a value in a property with a primitive" , ( ) => {
154+ it ( "overrides a value in a property with a non-nullish primitive" , ( ) => {
111155const first = { foo :{ bar :"baz" } } ;
112156const second = { foo :42 } ;
113157const result = merge ( first , second ) ;
114158
115- assert . deepStrictEqual ( result , first ) ;
116- assert . notStrictEqual ( result , first ) ;
159+ assert . deepStrictEqual ( result , second ) ;
160+ assert . notStrictEqual ( result , second ) ;
161+ confirmLegacyMergeResult ( first , second , result ) ;
117162} ) ;
118163
119- it ( "merges an object in a property with a string" , ( ) => {
164+ it ( "overrides an object in a property with a string" , ( ) => {
120165const first = { foo :{ bar :"baz" } } ;
121166const second = { foo :"qux" } ;
122167const result = merge ( first , second ) ;
123168
124- assert . deepStrictEqual ( result , { foo :{ 0 :"q" , 1 :"u" , 2 :"x" , bar :"baz" } } ) ;
169+ assert . deepStrictEqual ( result , second ) ;
170+ assert . notStrictEqual ( result , first ) ;
171+ confirmLegacyMergeResult ( first , second , result ) ;
172+ } ) ;
173+
174+ it ( "overrides a value in a property with a function" , ( ) => {
175+ const first = { someProperty :{ foo :42 } } ;
176+ const second = { someProperty ( ) { } } ;
177+ const result = merge ( first , second ) ;
178+
179+ assert . deepStrictEqual ( result , second ) ;
180+ assert . notProperty ( result . someProperty , "foo" ) ;
181+ confirmLegacyMergeResult ( first , second , result ) ;
182+ } ) ;
183+
184+ it ( "overrides a function in a property with an object" , ( ) => {
185+ const first = { someProperty :Object . assign ( ( ) => { } , { foo :"bar" } ) } ;
186+ const second = { someProperty :{ baz :"qux" } } ;
187+ const result = merge ( first , second ) ;
188+
189+ assert . deepStrictEqual ( result , second ) ;
190+ assert . notProperty ( result . someProperty , "foo" ) ;
191+ confirmLegacyMergeResult ( first , second , result ) ;
192+ } ) ;
193+
194+ it ( "sets properties to undefined" , ( ) => {
195+ const first = { foo :void 0 , bar :void 0 } ;
196+ const second = { foo :void 0 , baz :void 0 } ;
197+ const result = merge ( first , second ) ;
198+
199+ assert . deepStrictEqual ( result , { foo :void 0 , bar :void 0 , baz :void 0 } ) ;
200+ } ) ;
201+
202+ it ( "considers only own enumerable properties" , ( ) => {
203+ const first = {
204+ __proto__ :{ inherited1 :"A" } , // non-own properties are not considered
205+ included1 :"B" ,
206+ notMerged1 :{ first :true }
207+ } ;
208+ const second = {
209+ __proto__ :{ inherited2 :"C" } , // non-own properties are not considered
210+ included2 :"D" ,
211+ notMerged2 :{ second :true }
212+ } ;
213+
214+ // non-enumerable properties are not considered
215+ Object . defineProperty ( first , "notMerged2" , { enumerable :false , value :{ first :true } } ) ;
216+ Object . defineProperty ( second , "notMerged1" , { enumerable :false , value :{ second :true } } ) ;
217+
218+ const result = merge ( first , second ) ;
219+
220+ assert . deepStrictEqual (
221+ result ,
222+ {
223+ included1 :"B" ,
224+ included2 :"D" ,
225+ notMerged1 :{ first :true } ,
226+ notMerged2 :{ second :true }
227+ }
228+ ) ;
229+ confirmLegacyMergeResult ( first , second , result ) ;
125230} ) ;
126231
127232it ( "merges objects with self-references" , ( ) => {