@josundt/eslint-config 4.4.0 → 4.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +16 -14
- package/rules/eslint.js +34 -12
- package/rules/import-typescript.js +2 -1
- package/rules/typescript-eslint.js +104 -23
- package/utils/merge.js +93 -0
package/package.json
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
{
|
2
2
|
"name": "@josundt/eslint-config",
|
3
|
-
"version": "4.
|
3
|
+
"version": "4.7.3",
|
4
4
|
"description": "ESLint ruleset with required plugins for josundt TypeScript projects",
|
5
|
-
"main": ".
|
5
|
+
"main": "index.js",
|
6
6
|
"scripts": {
|
7
7
|
"lint": "echo \"No linting for this project\"",
|
8
8
|
"build": "echo \"No build for this project\"",
|
@@ -23,19 +23,21 @@
|
|
23
23
|
"license": "ISC",
|
24
24
|
"files": [
|
25
25
|
"*.js",
|
26
|
-
"rules/**/*.js"
|
26
|
+
"rules/**/*.js",
|
27
|
+
"utils/**/*.js"
|
27
28
|
],
|
28
29
|
"peerDependencies": {
|
29
|
-
"typescript": ">=4.
|
30
|
+
"typescript": ">=4.7.2"
|
30
31
|
},
|
31
32
|
"dependencies": {
|
32
|
-
"@typescript-eslint/eslint-plugin": "
|
33
|
-
"@typescript-eslint/parser": "
|
34
|
-
"eslint": "
|
35
|
-
"eslint-import-resolver-typescript": "2.
|
36
|
-
"eslint-plugin-deprecation": "1.2
|
37
|
-
"eslint-plugin-import": "2.
|
38
|
-
"eslint-plugin-jasmine": "4.1.
|
39
|
-
"eslint-plugin-jsdoc": "
|
40
|
-
"eslint-plugin-unicorn": "
|
41
|
-
}
|
33
|
+
"@typescript-eslint/eslint-plugin": "5.27.0",
|
34
|
+
"@typescript-eslint/parser": "5.27.0",
|
35
|
+
"eslint": "8.16.0",
|
36
|
+
"eslint-import-resolver-typescript": "2.7.1",
|
37
|
+
"eslint-plugin-deprecation": "1.3.2",
|
38
|
+
"eslint-plugin-import": "2.26.0",
|
39
|
+
"eslint-plugin-jasmine": "4.1.3",
|
40
|
+
"eslint-plugin-jsdoc": "39.3.2",
|
41
|
+
"eslint-plugin-unicorn": "42.0.0"
|
42
|
+
}
|
43
|
+
}
|
package/rules/eslint.js
CHANGED
@@ -61,7 +61,7 @@ module.exports = {
|
|
61
61
|
],
|
62
62
|
"guard-for-in": "error",
|
63
63
|
"handle-callback-err": "error",
|
64
|
-
"id-
|
64
|
+
"id-denylist": [
|
65
65
|
"error",
|
66
66
|
"any",
|
67
67
|
"Number",
|
@@ -86,7 +86,14 @@ module.exports = {
|
|
86
86
|
"FunctionExpression": {
|
87
87
|
"parameters": "first"
|
88
88
|
},
|
89
|
-
"SwitchCase": 1
|
89
|
+
"SwitchCase": 1,
|
90
|
+
|
91
|
+
// Fix to decorator indentation problem
|
92
|
+
"ignoredNodes": [
|
93
|
+
"FunctionExpression > .params[decorators.length > 0]",
|
94
|
+
"FunctionExpression > .params > :matches(Decorator, :not(:first-child))",
|
95
|
+
"ClassBody.body > PropertyDefinition[decorators.length > 0] > .key"
|
96
|
+
]
|
90
97
|
}
|
91
98
|
],
|
92
99
|
"init-declarations": "off",
|
@@ -134,7 +141,9 @@ module.exports = {
|
|
134
141
|
"no-duplicate-imports": "error",
|
135
142
|
"no-empty": "error",
|
136
143
|
"no-empty-character-class": "error",
|
137
|
-
"no-empty-function": "error",
|
144
|
+
"no-empty-function": ["error", {
|
145
|
+
//allow: [/*"functions", "arrowFunctions", "generatorFunctions", "methods", "generatorMethods", "getters", "setters", "constructors", "asyncFunctions", "asyncMethods"*/]
|
146
|
+
}],
|
138
147
|
"no-eval": "error",
|
139
148
|
"no-ex-assign": "error",
|
140
149
|
"no-extra-bind": "error",
|
@@ -198,7 +207,10 @@ module.exports = {
|
|
198
207
|
"no-shadow": [
|
199
208
|
"error",
|
200
209
|
{
|
201
|
-
"hoist": "all"
|
210
|
+
"hoist": "all",
|
211
|
+
"builtinGlobals": false,
|
212
|
+
"ignoreOnInitialization": false,
|
213
|
+
"allow": [] // array of identifier names for which shadowing is allowed
|
202
214
|
}
|
203
215
|
],
|
204
216
|
"no-sparse-arrays": "error",
|
@@ -219,7 +231,8 @@ module.exports = {
|
|
219
231
|
"error",
|
220
232
|
{
|
221
233
|
"vars": "all",
|
222
|
-
"args": "none"
|
234
|
+
"args": "none",
|
235
|
+
"destructuredArrayIgnorePattern": "^_"
|
223
236
|
}
|
224
237
|
],
|
225
238
|
"no-use-before-define": "error",
|
@@ -236,12 +249,17 @@ module.exports = {
|
|
236
249
|
"never"
|
237
250
|
],
|
238
251
|
"padding-line-between-statements": [
|
239
|
-
"
|
240
|
-
{
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
}
|
252
|
+
"error",
|
253
|
+
{ "blankLine": "always", "prev": ["directive", "import"], "next": "*" },
|
254
|
+
{ "blankLine": "any", "prev": ["directive", "import"], "next": ["directive", "import"] },
|
255
|
+
|
256
|
+
{ "blankLine": "always", "prev": "*", "next": ["export", "class", "function", "iife"] },
|
257
|
+
{ "blankLine": "always", "prev": ["export", "class", "function", "iife"], "next": "*" },
|
258
|
+
|
259
|
+
// { "blankLine": "always", "prev": "*", "next": "return" }, // Newline before return
|
260
|
+
|
261
|
+
// { "blankLine": "always", "prev": "*", "next": "multiline-block-like" }, // Newline BEFORE multiline block
|
262
|
+
// { "blankLine": "always", "prev": "multiline-block-like", "next": "*" } // Newline AFTER multiline block
|
245
263
|
],
|
246
264
|
"prefer-arrow-callback": "error",
|
247
265
|
"prefer-const": "error",
|
@@ -262,8 +280,12 @@ module.exports = {
|
|
262
280
|
"error",
|
263
281
|
"always"
|
264
282
|
],
|
283
|
+
"space-before-blocks": [
|
284
|
+
"error",
|
285
|
+
"always"
|
286
|
+
],
|
265
287
|
"space-before-function-paren": [
|
266
|
-
"
|
288
|
+
"error",
|
267
289
|
{
|
268
290
|
"anonymous": "always",
|
269
291
|
"asyncArrow": "always",
|
@@ -8,12 +8,13 @@ module.exports = {
|
|
8
8
|
"rules": {
|
9
9
|
"import/extensions": [ // Ensure all local .ts file imports use .js extension
|
10
10
|
"error",
|
11
|
-
"
|
11
|
+
"ignorePackages"
|
12
12
|
],
|
13
13
|
"import/no-commonjs": "error", // Disallow require() syntax - only esm syntax allowed
|
14
14
|
"import/no-nodejs-modules": "error", // Disallowed: import * as path from "path"; Allowed: import * as path from "node:path";
|
15
15
|
"import/no-default-export": "off",
|
16
16
|
"import/no-deprecated": "error",
|
17
|
+
"import/no-duplicates": "error",
|
17
18
|
"import/no-extraneous-dependencies": "off",
|
18
19
|
"import/no-internal-modules": "off",
|
19
20
|
"import/no-unassigned-import": "error",
|
@@ -1,9 +1,16 @@
|
|
1
|
-
const eslintRuleSet = require("./eslint");
|
1
|
+
const eslintRuleSet = require("./eslint.js");
|
2
|
+
const { deepMergeObjects } = require("../utils/merge.js");
|
3
|
+
|
2
4
|
const eslintRules = eslintRuleSet.rules;
|
3
5
|
|
4
6
|
// Map of all the typescript-eslint extensions.
|
5
|
-
// If extension rule has additional properties compared to standard eslint rule
|
6
|
-
//
|
7
|
+
// If extension rule has additional properties compared to standard eslint rule:
|
8
|
+
// If the map value is an object:
|
9
|
+
// The object will be merged merged with standard rule (rule object 1);
|
10
|
+
// If the map value is an array:
|
11
|
+
// The items of the array will be added as a new rule options object.
|
12
|
+
// If the map value is a function:
|
13
|
+
// The standard eslint options object will be passed as parameters, the return statement will be added as options.
|
7
14
|
const extensions = new Map([
|
8
15
|
["brace-style", null],
|
9
16
|
["comma-dangle", null],
|
@@ -23,38 +30,51 @@ const extensions = new Map([
|
|
23
30
|
}],
|
24
31
|
["no-array-constructor", null],
|
25
32
|
["no-dupe-class-members", null],
|
26
|
-
["no-
|
27
|
-
|
33
|
+
["no-empty-function", {
|
34
|
+
allow: ["private-constructors", "protected-constructors" /* "decoratedFunctions", "overrideMethods" */ ]
|
35
|
+
}],
|
28
36
|
["no-extra-parens", null],
|
29
37
|
["no-extra-semi", null],
|
30
38
|
["no-invalid-this", null],
|
31
39
|
["no-loop-func", null],
|
32
40
|
["no-loss-of-precision", null],
|
33
41
|
["no-magic-numbers", null],
|
34
|
-
["no-shadow", {
|
35
|
-
|
36
|
-
|
42
|
+
["no-shadow", v => {
|
43
|
+
const o = {
|
44
|
+
...v,
|
45
|
+
"ignoreTypeValueShadow": true,
|
46
|
+
"ignoreFunctionTypeParameterNameValueShadow": true
|
47
|
+
};
|
48
|
+
delete o["ignoreOnInitialization"]; // Temporary bug in @typescript/eslint "no-shadow" extension rule - "ignoreOnInitialization" property considered invalid
|
49
|
+
return o;
|
37
50
|
}],
|
38
51
|
["no-unused-expressions", null],
|
39
52
|
["no-unused-vars", null],
|
40
53
|
["no-use-before-define", null],
|
41
54
|
["no-useless-constructor", null],
|
42
55
|
["object-curly-spacing", null],
|
56
|
+
["padding-line-between-statements", [
|
57
|
+
{ "blankLine": "always", "prev": "*", "next": ["interface", "type"] },
|
58
|
+
{ "blankLine": "always", "prev": ["interface", "type"], "next": "*" }
|
59
|
+
]],
|
43
60
|
["quotes", null],
|
44
61
|
["require-await", null],
|
45
62
|
["return-await", null],
|
46
63
|
["semi", null],
|
64
|
+
["space-before-blocks", null],
|
47
65
|
["space-before-function-paren", null],
|
48
|
-
["space-infix-ops", null]
|
66
|
+
// ["space-infix-ops", null] // buggy with typescript (as of 5.27.0) -- switched off below
|
49
67
|
]);
|
50
68
|
|
51
69
|
switchOffExtensions = new Set([
|
52
70
|
"no-unused-vars",
|
53
71
|
"no-invalid-this",
|
54
72
|
"no-use-before-define",
|
55
|
-
"no-useless-constructor"
|
73
|
+
"no-useless-constructor",
|
74
|
+
"space-infix-ops"
|
56
75
|
]);
|
57
76
|
|
77
|
+
|
58
78
|
// Building eslint-typescript rules for existsing eslint rules and switching off original eslint rule
|
59
79
|
const extendedEslintRules = Object.entries(eslintRules).reduce((extRules, [key, value]) => {
|
60
80
|
|
@@ -73,8 +93,22 @@ const extendedEslintRules = Object.entries(eslintRules).reduce((extRules, [key,
|
|
73
93
|
} else {
|
74
94
|
// If extension rule has extended options, merge with standard eslint rule options:
|
75
95
|
if (extension !== null) {
|
76
|
-
value
|
77
|
-
value
|
96
|
+
// Ensure value is array if only severity string:
|
97
|
+
value = Array.isArray(value) ? [...value] : [value];
|
98
|
+
if (Array.isArray(extension)) {
|
99
|
+
value.push(...extension);
|
100
|
+
} else if (typeof extension === "object") {
|
101
|
+
// If array only contains severity string, push object
|
102
|
+
if (value.length === 1) {
|
103
|
+
value.push(extension);
|
104
|
+
// Else merge object
|
105
|
+
} else {
|
106
|
+
value[value.length - 1] = deepMergeObjects(value[value.length - 1], extension);
|
107
|
+
}
|
108
|
+
} else if (typeof extension === "function") {
|
109
|
+
const [, ...options] = value;
|
110
|
+
value[value.length - 1] = { ...extension(...options) };
|
111
|
+
}
|
78
112
|
}
|
79
113
|
// Add extension rule value with the @typescript-eslint key prefix
|
80
114
|
extRules[`@typescript-eslint/${key}`] = value;
|
@@ -117,7 +151,17 @@ module.exports = {
|
|
117
151
|
}
|
118
152
|
],
|
119
153
|
"@typescript-eslint/await-thenable": "error",
|
120
|
-
"@typescript-eslint/ban-ts-comment":
|
154
|
+
"@typescript-eslint/ban-ts-comment": [
|
155
|
+
"error",
|
156
|
+
{
|
157
|
+
"ts-expect-error": "allow-with-description",
|
158
|
+
"ts-ignore": true,
|
159
|
+
"ts-nocheck": true,
|
160
|
+
"ts-check": false,
|
161
|
+
"minimumDescriptionLength": 10,
|
162
|
+
//"descriptionFormat": "someformathere"
|
163
|
+
}
|
164
|
+
],
|
121
165
|
"@typescript-eslint/ban-tslint-comment": "error", // No longer use tslint - remove rules
|
122
166
|
"@typescript-eslint/ban-types": "off", // Can be used to ban certain types
|
123
167
|
"@typescript-eslint/consistent-indexed-object-style": ["error", "record"],
|
@@ -132,6 +176,7 @@ module.exports = {
|
|
132
176
|
"error",
|
133
177
|
"interface"
|
134
178
|
],
|
179
|
+
"@typescript-eslint/consistent-type-exports": "error",
|
135
180
|
"@typescript-eslint/consistent-type-imports": [
|
136
181
|
"off",
|
137
182
|
{
|
@@ -145,7 +190,8 @@ module.exports = {
|
|
145
190
|
"allowExpressions": true,
|
146
191
|
"allowTypedFunctionExpressions": true,
|
147
192
|
"allowHigherOrderFunctions": true,
|
148
|
-
"allowConciseArrowFunctionExpressionsStartingWithVoid": true
|
193
|
+
"allowConciseArrowFunctionExpressionsStartingWithVoid": true,
|
194
|
+
"allowedNames": []
|
149
195
|
}
|
150
196
|
],
|
151
197
|
"@typescript-eslint/explicit-member-accessibility": [
|
@@ -159,9 +205,9 @@ module.exports = {
|
|
159
205
|
{
|
160
206
|
"allowArgumentsExplicitlyTypedAsAny": false,
|
161
207
|
"allowDirectConstAssertionInArrowFunctions": true,
|
162
|
-
"allowedNames": [],
|
163
208
|
"allowHigherOrderFunctions": true,
|
164
209
|
"allowTypedFunctionExpressions": true,
|
210
|
+
"allowedNames": []
|
165
211
|
}
|
166
212
|
],
|
167
213
|
"@typescript-eslint/member-delimiter-style": [
|
@@ -233,6 +279,7 @@ module.exports = {
|
|
233
279
|
"ignoreArrowShorthand": true
|
234
280
|
}
|
235
281
|
],
|
282
|
+
"@typescript-eslint/no-duplicate-enum-values": "error",
|
236
283
|
"@typescript-eslint/no-dynamic-delete": "error",
|
237
284
|
"@typescript-eslint/no-empty-interface": "off",
|
238
285
|
"@typescript-eslint/no-explicit-any": "off",
|
@@ -249,20 +296,36 @@ module.exports = {
|
|
249
296
|
"allowAsThisParameter": true
|
250
297
|
}
|
251
298
|
],
|
299
|
+
"@typescript-eslint/no-meaningless-void-operator": "error",
|
252
300
|
"@typescript-eslint/no-misused-new": "error",
|
253
|
-
"@typescript-eslint/no-misused-promises":
|
301
|
+
"@typescript-eslint/no-misused-promises": [
|
302
|
+
"error",
|
303
|
+
{
|
304
|
+
checksConditionals: true,
|
305
|
+
checksSpreads: true,
|
306
|
+
checksVoidReturn: true // {
|
307
|
+
// arguments: true, //Disables checking an asynchronous function passed as argument where the parameter type expects a function that returns void
|
308
|
+
// attributes: true, //Disables checking an asynchronous function passed as a JSX attribute expected to be a function that returns void
|
309
|
+
// properties: true, //Disables checking an asynchronous function passed as an object property expected to be a function that returns void
|
310
|
+
// returns: true, //Disables checking an asynchronous function returned in a function whose return type is a function that returns void
|
311
|
+
// variables: true //Disables checking an asynchronous function used as a variable whose return type is a function that returns void
|
312
|
+
// }
|
313
|
+
}
|
314
|
+
],
|
254
315
|
"@typescript-eslint/no-namespace": "off",
|
316
|
+
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
|
255
317
|
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
|
256
318
|
"@typescript-eslint/no-non-null-assertion": "off",
|
257
|
-
"@typescript-eslint/no-
|
319
|
+
"@typescript-eslint/no-redundant-type-constituents": "error",
|
320
|
+
"@typescript-eslint/no-require-imports": "error",
|
321
|
+
"@typescript-eslint/no-this-alias": "error",
|
322
|
+
"@typescript-eslint/no-throw-literal": [
|
258
323
|
"error",
|
259
324
|
{
|
260
|
-
"
|
325
|
+
"allowThrowingAny": false, // Default is to allow throwing values of type any
|
326
|
+
"allowThrowingUnknown": true // Default is to allow throwing values of type unknown
|
261
327
|
}
|
262
328
|
],
|
263
|
-
"@typescript-eslint/no-require-imports": "error",
|
264
|
-
"@typescript-eslint/no-this-alias": "error",
|
265
|
-
"@typescript-eslint/no-throw-literal": "error",
|
266
329
|
"@typescript-eslint/no-type-alias": "off",
|
267
330
|
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
|
268
331
|
"@typescript-eslint/no-unnecessary-condition": "off", // allow runtime null checks etc even if reported not necessary by type system
|
@@ -276,8 +339,16 @@ module.exports = {
|
|
276
339
|
"@typescript-eslint/no-unsafe-member-access": "error",
|
277
340
|
"@typescript-eslint/no-unsafe-return": "error",
|
278
341
|
"@typescript-eslint/no-unused-vars-experimental": "off", // to strict with method params...
|
342
|
+
"@typescript-eslint/no-useless-empty-export": "error",
|
279
343
|
"@typescript-eslint/no-var-requires": "error",
|
280
344
|
"@typescript-eslint/non-nullable-type-assertion-style": "error",
|
345
|
+
"@typescript-eslint/parameter-properties": [
|
346
|
+
"error",
|
347
|
+
{
|
348
|
+
"prefer": "class-property", // or "parameter-property"
|
349
|
+
"allow": ["private readonly", "private", "protected readonly"]
|
350
|
+
}
|
351
|
+
],
|
281
352
|
"@typescript-eslint/prefer-as-const": "error",
|
282
353
|
"@typescript-eslint/prefer-enum-initializers": "error",
|
283
354
|
"@typescript-eslint/prefer-for-of": "error",
|
@@ -299,10 +370,20 @@ module.exports = {
|
|
299
370
|
"@typescript-eslint/restrict-plus-operands": [
|
300
371
|
"error",
|
301
372
|
{
|
302
|
-
"checkCompoundAssignments": true
|
373
|
+
"checkCompoundAssignments": true,
|
374
|
+
"allowAny": false
|
375
|
+
}
|
376
|
+
],
|
377
|
+
"@typescript-eslint/restrict-template-expressions": [
|
378
|
+
"error",
|
379
|
+
{
|
380
|
+
"allowNumber": true,
|
381
|
+
"allowBoolean": false,
|
382
|
+
"allowAny": false,
|
383
|
+
"allowNullish": false,
|
384
|
+
"allowRegExp": false
|
303
385
|
}
|
304
386
|
],
|
305
|
-
"@typescript-eslint/restrict-template-expressions": "error",
|
306
387
|
"@typescript-eslint/sort-type-union-intersection-members": "off",
|
307
388
|
"@typescript-eslint/strict-boolean-expressions": [
|
308
389
|
"off",
|
package/utils/merge.js
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
/**
|
2
|
+
*
|
3
|
+
* @param {any} o
|
4
|
+
* @returns o is {}
|
5
|
+
*/
|
6
|
+
function isPlainObject(value) {
|
7
|
+
return !!value &&
|
8
|
+
!!(value = Object.getPrototypeOf(value)) &&
|
9
|
+
!Object.getPrototypeOf(value);
|
10
|
+
}
|
11
|
+
|
12
|
+
/**
|
13
|
+
*
|
14
|
+
* @param {any[]} first
|
15
|
+
* @param {any[]} second
|
16
|
+
* @param {boolean} insertBoth
|
17
|
+
* @returns {any[]}
|
18
|
+
*/
|
19
|
+
function deepMergeArrays(first, second, insertBoth = true) {
|
20
|
+
let result = [];
|
21
|
+
for (let i = 0; i < Math.max(first.length, second.length); i++) {
|
22
|
+
if (i < second.length) {
|
23
|
+
if (i < first.length) {
|
24
|
+
if (Array.isArray(second[i])) {
|
25
|
+
if (Array.isArray(first[i])) {
|
26
|
+
result.push(deepMergeArrays(first[i], second[i]));
|
27
|
+
} else {
|
28
|
+
result.push(first[i]);
|
29
|
+
}
|
30
|
+
} else if (isPlainObject(second[i])) {
|
31
|
+
if (isPlainObject(first[i])) {
|
32
|
+
result.push(deepMergeObjects(first[i], second[i]));
|
33
|
+
} else {
|
34
|
+
result.push(first[i]);
|
35
|
+
}
|
36
|
+
} else {
|
37
|
+
if (first[i] === second[i] && !insertBoth) {
|
38
|
+
result.push(first[i]);
|
39
|
+
} else {
|
40
|
+
result.push(first[i], second[i]);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
} else {
|
44
|
+
result.push(second[i]);
|
45
|
+
}
|
46
|
+
} else {
|
47
|
+
result.push(first[i]);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
return result;
|
51
|
+
}
|
52
|
+
|
53
|
+
/**
|
54
|
+
*
|
55
|
+
* @param {{}} first
|
56
|
+
* @param {{}} second
|
57
|
+
* @returns {{}}
|
58
|
+
*/
|
59
|
+
function deepMergeObjects(first, second) {
|
60
|
+
const result = {};
|
61
|
+
const remainingKeysFromSecond = new Set(Object.keys(second));
|
62
|
+
for (const key of Object.keys(first)) {
|
63
|
+
if (remainingKeysFromSecond.has(key)) {
|
64
|
+
if (Array.isArray(first[key])) {
|
65
|
+
if (Array.isArray(second[key])) {
|
66
|
+
result[key] = deepMergeArrays(first[key], second[key]);
|
67
|
+
} else {
|
68
|
+
result[key] = first[key];
|
69
|
+
}
|
70
|
+
} else if (isPlainObject(first[key])) {
|
71
|
+
if (isPlainObject(second[key])) {
|
72
|
+
result[key] = deepMergeObjects(first[key], second[key]);
|
73
|
+
} else {
|
74
|
+
result[key] = first[key];
|
75
|
+
}
|
76
|
+
} else {
|
77
|
+
result[key] = first[key];
|
78
|
+
}
|
79
|
+
remainingKeysFromSecond.delete(key);
|
80
|
+
} else {
|
81
|
+
result[key] = first[key];
|
82
|
+
}
|
83
|
+
}
|
84
|
+
for (const key of Array.from(remainingKeysFromSecond)) {
|
85
|
+
result[key] = second[key];
|
86
|
+
}
|
87
|
+
return result;
|
88
|
+
}
|
89
|
+
|
90
|
+
module.exports = {
|
91
|
+
deepMergeObjects,
|
92
|
+
deepMergeArrays
|
93
|
+
};
|