eslint-plugin-remeda 1.0.0

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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -0
  3. package/docs/rules/collection-method-value.md +27 -0
  4. package/docs/rules/collection-return.md +29 -0
  5. package/docs/rules/prefer-constant.md +53 -0
  6. package/docs/rules/prefer-do-nothing.md +29 -0
  7. package/docs/rules/prefer-filter.md +25 -0
  8. package/docs/rules/prefer-find.md +39 -0
  9. package/docs/rules/prefer-flat-map.md +25 -0
  10. package/docs/rules/prefer-is-empty.md +39 -0
  11. package/docs/rules/prefer-is-nil.md +27 -0
  12. package/docs/rules/prefer-map.md +29 -0
  13. package/docs/rules/prefer-nullish-coalescing.md +25 -0
  14. package/docs/rules/prefer-remeda-typecheck.md +36 -0
  15. package/docs/rules/prefer-some.md +29 -0
  16. package/docs/rules/prefer-times.md +36 -0
  17. package/package.json +62 -0
  18. package/src/index.js +35 -0
  19. package/src/rules/collection-method-value.js +82 -0
  20. package/src/rules/collection-return.js +71 -0
  21. package/src/rules/prefer-constant.js +87 -0
  22. package/src/rules/prefer-do-nothing.js +44 -0
  23. package/src/rules/prefer-filter.js +82 -0
  24. package/src/rules/prefer-find.js +68 -0
  25. package/src/rules/prefer-flat-map.js +50 -0
  26. package/src/rules/prefer-is-empty.js +134 -0
  27. package/src/rules/prefer-is-nil.js +97 -0
  28. package/src/rules/prefer-map.js +62 -0
  29. package/src/rules/prefer-nullish-coalescing.js +63 -0
  30. package/src/rules/prefer-remeda-typecheck.js +93 -0
  31. package/src/rules/prefer-some.js +43 -0
  32. package/src/rules/prefer-times.js +37 -0
  33. package/src/util/LodashContext.js +128 -0
  34. package/src/util/astUtil.js +353 -0
  35. package/src/util/getDocsUrl.js +17 -0
  36. package/src/util/importUtil.js +24 -0
  37. package/src/util/lodashUtil.js +123 -0
  38. package/src/util/methodData.js +2417 -0
  39. package/src/util/methodDataUtil.js +115 -0
  40. package/src/util/ruleUtil.js +13 -0
  41. package/src/util/settingsUtil.js +31 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Andrea Pontrandolfo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # 🚧 UNDER CONSTRUCTION 🚧
2
+
3
+ This library is still under construction. Don't use this in production yet. If you want to contribute, look at the open issues.
4
+
5
+ # ESLint Plugin Remeda
6
+
7
+ ESLint plugin for [Remeda](https://github.com/remeda/remeda).
8
+
9
+ ## Installation
10
+
11
+ First, you'll first need to install [ESLint](https://eslint.org/):
12
+
13
+ ```sh
14
+ npm add eslint -D
15
+ ```
16
+
17
+ Next, install `eslint-plugin-remeda`:
18
+
19
+ ```sh
20
+ npm add eslint-plugin-remeda -D
21
+ ```
22
+
23
+ ## Preamble
24
+
25
+ This plugin was originally derived from [eslint-plugin-lodash-f](https://github.com/AndreaPontrandolfo/eslint-plugin-lodash) (fork of [eslint-plugin-lodash](https://github.com/wix-incubator/eslint-plugin-lodash)) and used that as a base to build upon.
26
+
27
+ ## Rules
28
+
29
+ Enable all of the rules that you would like to use. All rules are off by default, unless you use one of the plugin's configurations which turn all relevant rules on.
30
+
31
+ - [collection-method-value](docs/rules/collection-method-value.md): Use value returned from collection methods properly.
32
+ - [collection-return](docs/rules/collection-return.md): Always return a value in iteratees of Remeda collection methods that aren't `forEach`.
33
+ - [prefer-filter](docs/rules/prefer-filter.md): Prefer `R.filter` over `R.forEach` with an `if` statement inside.
34
+ - [prefer-find](docs/rules/prefer-find.md): Prefer `R.find` over `R.filter` followed by selecting the first result.
35
+ - [prefer-flat-map](docs/rules/prefer-flat-map.md): Prefer `R.flatMap` over consecutive `map` and `flatten`.
36
+ - [prefer-map](docs/rules/prefer-map.md): Prefer `R.map` over `R.forEach` with a `push` inside.
37
+ - [prefer-nullish-coalescing](docs/rules/prefer-nullish-coalescing.md): Prefer `??` when doing a comparison with a non-nullish value as test.
38
+ - [prefer-constant](docs/rules/prefer-constant.md): Prefer `R.constant` over functions returning literals.
39
+ - [prefer-is-empty](docs/rules/prefer-is-empty.md): Prefer `R.isEmpty` over manual checking for length value.
40
+ - [prefer-is-nil](docs/rules/prefer-is-nil.md): Prefer `R.isNil` over checks for both null and undefined.
41
+ - [prefer-remeda-typecheck](docs/rules/prefer-remeda-typecheck.md): Prefer using `R.is*` methods over `typeof` and `instanceof` checks when applicable.
42
+ - [prefer-do-nothing](docs/rules/prefer-do-nothing.md): Prefer `R.doNothing` over empty functions.
43
+ - [prefer-some](docs/rules/prefer-some.md): Prefer using `R.some` over comparing `findIndex` to -1.
44
+ - [prefer-times](docs/rules/prefer-times.md): Prefer `R.times` over `R.map` without using the iteratee's arguments.
45
+
46
+ ## Contributing
47
+
48
+ Contributions are always welcome! For more info, read our [contribution guide](.github/CONTRIBUTING.md).
@@ -0,0 +1,27 @@
1
+ # Collection Method Value
2
+
3
+ When using a Remeda collection method, the expression should be used (e.g. assigning to a variable or check in a condition), unless it's a method meant for side effects (e.g. `forEach` or `forOwn`) which should NOT be used.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ x = R.forEach(arr, g);
13
+
14
+ R.map(arr, f);
15
+ ```
16
+
17
+ The following patterns are not considered warnings:
18
+
19
+ ```js
20
+ x = R.map(arr, f);
21
+
22
+ R.forEach(arr, g);
23
+
24
+ if (R.some(arr, h)) {
25
+ i();
26
+ }
27
+ ```
@@ -0,0 +1,29 @@
1
+ # Collection Return Statement
2
+
3
+ When using a Remeda collection method that isn't forEach, the iteratee should return a value, otherwise it could result in either unclear code or unexpected results.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+
13
+ R.map(arr, function(x) { console.log(x); });
14
+
15
+ R.some(arr, function(x) { if (x.a) {f(x); });
16
+
17
+ R.every(collection, x => { f(x); });
18
+
19
+ ```
20
+
21
+ The following patterns are not considered warnings:
22
+
23
+ ```js
24
+ R.map((x) => x + 1);
25
+
26
+ R.forEach(arr, function (a) {
27
+ console.log(a);
28
+ });
29
+ ```
@@ -0,0 +1,53 @@
1
+ # Prefer constant
2
+
3
+ When you want a function that always returns the same value, it can be more concise to use `R.constant`.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes two arguments:
8
+
9
+ - whether or not to check arrow functions
10
+ - whether or not to check function declarations (named functions)
11
+
12
+ The following patterns are considered warnings:
13
+
14
+ ```js
15
+ var three = function () {
16
+ return 3;
17
+ };
18
+ //Including arrow functions:
19
+ /*eslint remeda/prefer-constant: [2, true]*/
20
+ var pi = () => 3.1415;
21
+
22
+ //Including function declarations
23
+ /*eslint remeda/prefer-constant: [2, true, true]*/
24
+ function one() {
25
+ return 1;
26
+ }
27
+ ```
28
+
29
+ The following patterns are not considered warnings:
30
+
31
+ ```js
32
+ var identity = function (x) {
33
+ return x;
34
+ };
35
+
36
+ var getObj = function () {
37
+ return { a: 1 };
38
+ };
39
+ ```
40
+
41
+ The last example is not a warning because it is not equivalent to `R.constant({a:1})`, which always returns the same instance.
42
+ Consider:
43
+
44
+ ```js
45
+ var getObj = R.constant({ a: 1 });
46
+ x = getObj();
47
+ x.a = 2;
48
+ console.log(getObj()); // ==> {a:2}
49
+ ```
50
+
51
+ ## When Not To Use It
52
+
53
+ If you do not want to enforce using `R.constant`, you should not use this rule.
@@ -0,0 +1,29 @@
1
+ # Prefer noop
2
+
3
+ When defining an empty function (e.g. for callbacks) it can be more readable to use `R.doNothing()` or `R.constant(undefined)` instead. Use `R.doNothing()` if you need to return void, otherwise use `R.constant(undefined)`.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ functionWithCallback(function () {});
13
+
14
+ const emptyFunction = () => {};
15
+ ```
16
+
17
+ The following patterns are not considered warnings:
18
+
19
+ ```js
20
+ functionWithCallback(function (x) {
21
+ return x + 1;
22
+ });
23
+
24
+ const sqr = (x) => x * x;
25
+ ```
26
+
27
+ ## When Not To Use It
28
+
29
+ If you do not want to enforce using `R.doNothing`, you should not use this rule.
@@ -0,0 +1,25 @@
1
+ # Prefer filter
2
+
3
+ When using R.forEach with a single `if` statement, you should probably use `R.filter` or `R.some` instead.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes one argument, maximum path length (default is 3).
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ R.forEach(users, function (user) {
13
+ if (user.name.givenName === "Bob") {
14
+ // ...
15
+ }
16
+ });
17
+ ```
18
+
19
+ The following patterns are not considered warnings:
20
+
21
+ ```js
22
+ const x = R.filter(users, function (user) {
23
+ return !user.active && user.name.givenName === "Bob";
24
+ });
25
+ ```
@@ -0,0 +1,39 @@
1
+ # Prefer find
2
+
3
+ When using R.filter and accessing the first or last result, you should probably use `R.find` or `R.findLast`, respectively.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ const x = R.filter(a, f)[0];
13
+ ```
14
+
15
+ ```js
16
+ const x = R.head(R.filter(a, f));
17
+ ```
18
+
19
+ ```js
20
+ const x = R.last(R.filter(a, f));
21
+ ```
22
+
23
+ ```js
24
+ const x = R.head(R.reject(a, f));
25
+ ```
26
+
27
+ The following patterns are not considered warnings:
28
+
29
+ ```js
30
+ const x = R.filter(a, f);
31
+ ```
32
+
33
+ ```js
34
+ const x = R.filter(a, f)[3];
35
+ ```
36
+
37
+ ```js
38
+ const x = R.find(a, f);
39
+ ```
@@ -0,0 +1,25 @@
1
+ # Prefer [`R.flatMap`] over consecutive [`R.map`] and [`R.flatten`]
2
+
3
+ When using [`R.map`] and [`R.flatten`], it can be more concise to use [`R.flatMap`] instead.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ t = R.flatten(R.map(a, f));
13
+ ```
14
+
15
+ The following patterns are not considered warnings:
16
+
17
+ ```js
18
+ t = R.map(a, f);
19
+
20
+ t = R.flatMap(a, f);
21
+ ```
22
+
23
+ ## When Not To Use It
24
+
25
+ If you do not want to enforce using [`R.flatMap`], and prefer [`R.map`] and [`R.flatten`] instead, you should not use this rule.
@@ -0,0 +1,39 @@
1
+ # Prefer R.isEmpty
2
+
3
+ When checking if a collection is empty or no, it is more concise to use R.isEmpty instead.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ const myLengthEqualZero = myVar.length === 0;
13
+
14
+ const myLengthEqualZero = myVar.length > 0;
15
+
16
+ const myLengthEqualZero = myVar.length > 0 ? "first" : "second";
17
+
18
+ const myLengthEqualZero = myVar.myProp.mySecondProp.length === 0;
19
+
20
+ const myLengthEqualZero = myVar.myProp.mySecondProp.length > 0;
21
+ ```
22
+
23
+ The following patterns are not considered warnings:
24
+
25
+ ```js
26
+ const myLengthEqualZero = !isEmpty(myVar);
27
+
28
+ const myLengthEqualZero = isEmpty(myVar);
29
+
30
+ const myLengthEqualZero = myVar.length == 0;
31
+
32
+ const myLengthEqualZero = myVar.length;
33
+
34
+ const myLengthEqualZero = myVar;
35
+ ```
36
+
37
+ ## When Not To Use It
38
+
39
+ If you do not want to enforce using `R.isEmpty`, and prefer using native checks instead.
@@ -0,0 +1,27 @@
1
+ # Prefer R.isNil
2
+
3
+ When checking that a value is undefined or null (but not false or ''), it is more concise to use R.isNil instead.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ var t = !R.isNull(x) && !R.isUndefined(x);
13
+
14
+ var t = x === undefined || x === null;
15
+ ```
16
+
17
+ The following patterns are not considered warnings:
18
+
19
+ ```js
20
+ var t = R.isNil(x);
21
+
22
+ var t = R.isUndefined(x) || R.isNull(y);
23
+ ```
24
+
25
+ ## When Not To Use It
26
+
27
+ If you do not want to enforce using `R.isNil`, and prefer using specific checks instead.
@@ -0,0 +1,29 @@
1
+ # Prefer map
2
+
3
+ When using `R.forEach` that pushes into an array, it could improve readability to use `R.map` instead.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ R.forEach(arr, function (x) {
13
+ newArr.push(f(x));
14
+ });
15
+ ```
16
+
17
+ The following patterns are not considered warnings:
18
+
19
+ ```js
20
+ R.forEach(arr, function (x) {
21
+ if (x.a) {
22
+ a.push(x);
23
+ }
24
+ });
25
+ ```
26
+
27
+ ## When Not To Use It
28
+
29
+ If you do not want to enforce using `map`, you should not use this rule.
@@ -0,0 +1,25 @@
1
+ # Prefer nullish coalescing over checking a ternary with !isNil.
2
+
3
+ When checking if a variable is not nil as a test for a ternary equation, it's more coincise to just use the nullish coalescing operator.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ const myExpression = !isNil(myVar) ? myVar : myOtherVar;
13
+ ```
14
+
15
+ The following patterns are not considered warnings:
16
+
17
+ ```js
18
+ const myExpression = !isNil(myVar) ? mySecondVar : myThirdVar;
19
+
20
+ const myExpression = myVar ?? myOtherVar;
21
+ ```
22
+
23
+
24
+ ## When Not To Use It
25
+ If you do not want to enforce using nullish coalescing.
@@ -0,0 +1,36 @@
1
+ # Prefer Lodash typecheck
2
+
3
+ Getting the specific type of a variable or expression can be done with `typeof` or `instanceof`. However, it's often more expressive to use the Lodash equivalent function
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+
13
+ if (typeof a === 'number') {
14
+ // ...
15
+ }
16
+
17
+ var isNotString = typeof b !== 'string';
18
+
19
+ var isArray = a instanceof Array;
20
+
21
+ ```
22
+
23
+ The following patterns are not considered warnings:
24
+
25
+ ```js
26
+
27
+ var areSameType = typeof a === typeof b;
28
+
29
+ var isCar = truck instanceof Car;
30
+
31
+ ```
32
+
33
+
34
+ ## When Not To Use It
35
+
36
+ If you do not want to enforce using Lodash methods for type checks, you should not use this rule.
@@ -0,0 +1,29 @@
1
+ # Prefer R.some
2
+
3
+ When comparing the index of an item with an `findIndex` method, it can be more expressive to use `R.some`, when only the sole existence of a matching item is taken into account.
4
+
5
+ ## Rule Details
6
+
7
+ The following patterns are considered warnings:
8
+
9
+ ```js
10
+ var a = R.findIndex(b, f) === -1;
11
+
12
+ var a = R.findIndex(b, f) >= 0;
13
+ ```
14
+
15
+ The following patterns are not considered warnings:
16
+
17
+ ```js
18
+ x = R.findIndex(a, f);
19
+
20
+ R.findIndex(a, f) === 2;
21
+
22
+ if (R.some(a, f)) {
23
+ // ...
24
+ }
25
+ ```
26
+
27
+ ## When Not To Use It
28
+
29
+ If you do not want to enforce using `R.findIndex`, you should not use this rule.
@@ -0,0 +1,36 @@
1
+ # Prefer R.times
2
+
3
+ When using `R.map` in which the iteratee does not have any arguments, it's better to use `R.times`.
4
+
5
+ ## Rule Details
6
+
7
+ This rule takes no arguments.
8
+
9
+ The following patterns are considered warnings:
10
+
11
+ ```js
12
+ R.map(arr, function () {
13
+ return 7;
14
+ });
15
+
16
+ R.map(Array(10), function () {
17
+ return f(y);
18
+ });
19
+
20
+ import f from "remeda/map";
21
+ f(arr, () => 0);
22
+ ```
23
+
24
+ The following patterns are not considered warnings:
25
+
26
+ ```js
27
+ R.times(arr.length, R.constant(7));
28
+
29
+ R.map(arr, function (x) {
30
+ return x * x;
31
+ });
32
+ ```
33
+
34
+ ## When Not To Use It
35
+
36
+ If you do not want to enforce always using `times` when not using the arguments, you should not use this rule.
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "eslint-plugin-remeda",
3
+ "version": "1.0.0",
4
+ "author": "Andrea Pontrandolfo <andrea.pontra@gmail.com>",
5
+ "description": "ESLint plugin for Remeda library.",
6
+ "type": "commonjs",
7
+ "main": "src/index.js",
8
+ "scripts": {
9
+ "coveralls": "nyc report --reporter=text-lcov | coveralls",
10
+ "knip": "knip",
11
+ "publint": "publint",
12
+ "test": "npm run unit-test",
13
+ "unit-test": "cross-env nyc mocha \"tests/**/*.js\" --reporter=dot",
14
+ "semantic-release": "semantic-release"
15
+ },
16
+ "files": [
17
+ "README.md",
18
+ "src",
19
+ "docs"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/AndreaPontrandolfo/eslint-plugin-remeda"
24
+ },
25
+ "homepage": "https://github.com/AndreaPontrandolfo/eslint-plugin-remeda",
26
+ "bugs": "https://github.com/AndreaPontrandolfo/eslint-plugin-remeda/issues",
27
+ "peerDependencies": {
28
+ "eslint": ">=2"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^20.14.9",
32
+ "auto-changelog": "^2.4.0",
33
+ "coveralls": "^3.1.1",
34
+ "cross-env": "^7.0.3",
35
+ "eslint": "^8.16.0",
36
+ "eslint-config-wix-editor": "^8.4.2",
37
+ "eslint-import-resolver-node": "^0.3.6",
38
+ "eslint-plugin-eslint-plugin": "^4.2.0",
39
+ "eslint-plugin-import": "^2.26.0",
40
+ "eslint-traverser": "^1.5.2",
41
+ "knip": "^5.23.2",
42
+ "mocha": "^9.2.2",
43
+ "nyc": "^15.1.0",
44
+ "prettier": "^3.3.2",
45
+ "publint": "^0.2.8",
46
+ "semantic-release": "^24.0.0",
47
+ "typescript": "^5.5.2"
48
+ },
49
+ "engines": {
50
+ "node": ">=20"
51
+ },
52
+ "keywords": [
53
+ "eslint",
54
+ "eslint-plugin",
55
+ "eslintplugin",
56
+ "remeda"
57
+ ],
58
+ "license": "MIT",
59
+ "dependencies": {
60
+ "lodash": "^4.17.21"
61
+ }
62
+ }
package/src/index.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const _ = require("lodash");
5
+ const rules = fs
6
+ .readdirSync(path.resolve(__dirname, "rules"))
7
+ .map((f) => f.replace(/\.js$/, ""));
8
+ const recommended = {
9
+ plugins: ["remeda"],
10
+ rules: {
11
+ "remeda/prefer-is-empty": 2,
12
+ "remeda/prefer-is-nil": 2,
13
+ "remeda/prefer-times": 2,
14
+ "remeda/prefer-constant": 2,
15
+ "remeda/prefer-remeda-typecheck": 2,
16
+ "remeda/prefer-nullish-coalescing": 2,
17
+ "remeda/prefer-filter": [2, 3],
18
+ "remeda/collection-method-value": 2,
19
+ "remeda/collection-return": 2,
20
+ "remeda/prefer-map": 2,
21
+ "remeda/prefer-find": 2,
22
+ "remeda/prefer-some": 2,
23
+ "remeda/prefer-flat-map": 2,
24
+ "remeda/prefer-do-nothing": 2,
25
+ },
26
+ };
27
+ module.exports = {
28
+ rules: _.zipObject(
29
+ rules,
30
+ rules.map((rule) => require(`./rules/${rule}`)),
31
+ ),
32
+ configs: {
33
+ recommended,
34
+ },
35
+ };