Repository: exadel-inc/esl
Pull request #2325 (2024-04-09 11:02:34)

[maintain] Porting `attr` related changes for `4.16.0`
Porting 
- #2184
- #2228

for 4-th version


codeclimate[bot]: Code Climate has analyzed commit 5ad5c649 and detected **1 issue** on this pull request.

Here's the issue category breakdown:

| Category | Count |
|:---:|:---:|
| Complexity | 1 |


The test coverage on the diff in this pull request is **100.0%** (**50%** is the threshold).

This pull request will bring the total coverage in the repository to **64.6%** (**0.0%** change).

View more on [Code Climate](https://codeclimate.com/github/exadel-inc/esl/pull/2325).


Patch:
diff --git a/package-lock.json b/package-lock.json
index 8e7da1714..8d5d3852f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,12 +24,12 @@
         "@semantic-release/changelog": "^6.0.3",
         "@semantic-release/commit-analyzer": "^12.0.0",
         "@semantic-release/git": "^10.0.1",
-        "@semantic-release/github": "^10.0.3",
+        "@semantic-release/github": "^10.0.2",
         "@semantic-release/npm": "^12.0.0",
         "@semantic-release/release-notes-generator": "^13.0.0",
         "@types/jest": "^29.5.12",
-        "@typescript-eslint/eslint-plugin": "^7.6.0",
-        "@typescript-eslint/parser": "^7.6.0",
+        "@typescript-eslint/eslint-plugin": "^7.5.0",
+        "@typescript-eslint/parser": "^7.5.0",
         "chokidar-cli": "^3.0.0",
         "concurrently": "^8.2.2",
         "copyfiles": "^2.4.1",
@@ -125,7 +125,7 @@
         "@types/puppeteer": "^7.0.4",
         "jest-image-snapshot": "^6.4.0",
         "jest-puppeteer": "^10.0.1",
-        "puppeteer": "^22.6.3",
+        "puppeteer": "^22.6.2",
         "stucumber": "^0.19.0"
       }
     },
@@ -2866,12 +2866,12 @@
       "dev": true
     },
     "node_modules/@octokit/plugin-paginate-rest": {
-      "version": "11.0.0",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.0.0.tgz",
-      "integrity": "sha512-HLz6T9HWeNkX3SVqc7FUYlh+TAg3G7gCc1MGuNcov8mSrFU9dc4ABmRmgqR9TsY1doUx42vLN5UxxWlnqBX8xw==",
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-10.0.0.tgz",
+      "integrity": "sha512-G1Z67qOiFneKDJyMafHQkWnKm1kU3FfbRZLzxgsFg4dOa3pRNdABbdk+xo/oev6P88lnbt7GKdBNB6dJZuPphA==",
       "dev": true,
       "dependencies": {
-        "@octokit/types": "^13.0.0"
+        "@octokit/types": "^12.6.0"
       },
       "engines": {
         "node": ">= 18"
@@ -2880,21 +2880,6 @@
         "@octokit/core": ">=6"
       }
     },
-    "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
-      "version": "21.2.0",
-      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-21.2.0.tgz",
-      "integrity": "sha512-xx+Xd6I7rYvul/hgUDqv6TeGX0IOGnhSg9IOeYgd/uI7IAqUy6DE2B6Ipv2M4mWoxaMcWjIzgTIcv8pMO3F3vw==",
-      "dev": true
-    },
-    "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
-      "version": "13.1.0",
-      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.1.0.tgz",
-      "integrity": "sha512-nBwAFOYqVUUJ2AZFK4ZzESQptaAVqdTDKk8gE0Xr0o99WuPDSrhUC38x0F40xD9OUxXhOOuZKWNNVVLPSHQDvQ==",
-      "dev": true,
-      "dependencies": {
-        "@octokit/openapi-types": "^21.0.0"
-      }
-    },
     "node_modules/@octokit/plugin-retry": {
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.0.3.tgz",
@@ -3097,13 +3082,13 @@
       }
     },
     "node_modules/@semantic-release/github": {
-      "version": "10.0.3",
-      "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-10.0.3.tgz",
-      "integrity": "sha512-nSJQboKrG4xBn7hHpRMrK8lt5DgqJg50ZMz9UbrsfTxuRk55XVoQEadbGZ2L9M0xZAC6hkuwkDhQJKqfPU35Fw==",
+      "version": "10.0.2",
+      "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-10.0.2.tgz",
+      "integrity": "sha512-SP5ihhv/uQa8vPuWKmbJrrzfv8lRUkDFC6qwgaWoorrflN1DEW0IGCa9w/PxUp8Ad3dbvXZPmpXdGiP3eyTzhg==",
       "dev": true,
       "dependencies": {
         "@octokit/core": "^6.0.0",
-        "@octokit/plugin-paginate-rest": "^11.0.0",
+        "@octokit/plugin-paginate-rest": "^10.0.0",
         "@octokit/plugin-retry": "^7.0.0",
         "@octokit/plugin-throttling": "^9.0.0",
         "@semantic-release/error": "^4.0.0",
@@ -3981,22 +3966,22 @@
       "integrity": "sha512-d4GpH4uPYp9W07kc487tiq6V/EUHl18vZWFMbQoe4Sk9LXEWzFi/BMf9x7TI4m7/j7gU3KeX8H6M8aPBgykeLw=="
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz",
-      "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==",
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz",
+      "integrity": "sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==",
       "dev": true,
       "dependencies": {
-        "@eslint-community/regexpp": "^4.10.0",
-        "@typescript-eslint/scope-manager": "7.6.0",
-        "@typescript-eslint/type-utils": "7.6.0",
-        "@typescript-eslint/utils": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0",
+        "@eslint-community/regexpp": "^4.5.1",
+        "@typescript-eslint/scope-manager": "7.5.0",
+        "@typescript-eslint/type-utils": "7.5.0",
+        "@typescript-eslint/utils": "7.5.0",
+        "@typescript-eslint/visitor-keys": "7.5.0",
         "debug": "^4.3.4",
         "graphemer": "^1.4.0",
-        "ignore": "^5.3.1",
+        "ignore": "^5.2.4",
         "natural-compare": "^1.4.0",
-        "semver": "^7.6.0",
-        "ts-api-utils": "^1.3.0"
+        "semver": "^7.5.4",
+        "ts-api-utils": "^1.0.1"
       },
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -4016,15 +4001,15 @@
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz",
-      "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==",
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.5.0.tgz",
+      "integrity": "sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "7.6.0",
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/typescript-estree": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0",
+        "@typescript-eslint/scope-manager": "7.5.0",
+        "@typescript-eslint/types": "7.5.0",
+        "@typescript-eslint/typescript-estree": "7.5.0",
+        "@typescript-eslint/visitor-keys": "7.5.0",
         "debug": "^4.3.4"
       },
       "engines": {
@@ -4044,13 +4029,13 @@
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz",
-      "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==",
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz",
+      "integrity": "sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0"
+        "@typescript-eslint/types": "7.5.0",
+        "@typescript-eslint/visitor-keys": "7.5.0"
       },
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -4061,15 +4046,15 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz",
-      "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==",
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz",
+      "integrity": "sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "7.6.0",
-        "@typescript-eslint/utils": "7.6.0",
+        "@typescript-eslint/typescript-estree": "7.5.0",
+        "@typescript-eslint/utils": "7.5.0",
         "debug": "^4.3.4",
-        "ts-api-utils": "^1.3.0"
+        "ts-api-utils": "^1.0.1"
       },
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -4088,9 +4073,9 @@
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz",
-      "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==",
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.5.0.tgz",
+      "integrity": "sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==",
       "dev": true,
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -4101,19 +4086,19 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz",
-      "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==",
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz",
+      "integrity": "sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/visitor-keys": "7.6.0",
+        "@typescript-eslint/types": "7.5.0",
+        "@typescript-eslint/visitor-keys": "7.5.0",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
-        "minimatch": "^9.0.4",
-        "semver": "^7.6.0",
-        "ts-api-utils": "^1.3.0"
+        "minimatch": "9.0.3",
+        "semver": "^7.5.4",
+        "ts-api-utils": "^1.0.1"
       },
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -4158,18 +4143,18 @@
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz",
-      "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==",
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.5.0.tgz",
+      "integrity": "sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
-        "@types/json-schema": "^7.0.15",
-        "@types/semver": "^7.5.8",
-        "@typescript-eslint/scope-manager": "7.6.0",
-        "@typescript-eslint/types": "7.6.0",
-        "@typescript-eslint/typescript-estree": "7.6.0",
-        "semver": "^7.6.0"
+        "@types/json-schema": "^7.0.12",
+        "@types/semver": "^7.5.0",
+        "@typescript-eslint/scope-manager": "7.5.0",
+        "@typescript-eslint/types": "7.5.0",
+        "@typescript-eslint/typescript-estree": "7.5.0",
+        "semver": "^7.5.4"
       },
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -4183,13 +4168,13 @@
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz",
-      "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==",
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz",
+      "integrity": "sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "7.6.0",
-        "eslint-visitor-keys": "^3.4.3"
+        "@typescript-eslint/types": "7.5.0",
+        "eslint-visitor-keys": "^3.4.1"
       },
       "engines": {
         "node": "^18.18.0 || >=20.0.0"
@@ -4923,12 +4908,13 @@
       "optional": true
     },
     "node_modules/bare-fs": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.3.tgz",
-      "integrity": "sha512-amG72llr9pstfXOBOHve1WjiuKKAMnebcmMbPWDZ7BCevAoJLpugjuAPRsDINEyjT0a6tbaVx3DctkXIRbLuJw==",
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.2.2.tgz",
+      "integrity": "sha512-X9IqgvyB0/VA5OZJyb5ZstoN62AzD7YxVGog13kkfYWYqJYcK0kcqLZ6TrmH5qr4/8//ejVcX4x/a0UvaogXmA==",
       "optional": true,
       "dependencies": {
         "bare-events": "^2.0.0",
+        "bare-os": "^2.0.0",
         "bare-path": "^2.0.0",
         "streamx": "^2.13.0"
       }
@@ -4940,9 +4926,9 @@
       "optional": true
     },
     "node_modules/bare-path": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.1.tgz",
-      "integrity": "sha512-OHM+iwRDRMDBsSW7kl3dO62JyHdBKO3B25FB9vNQBPcGHMo4+eA8Yj41Lfbk3pS/seDY+siNge0LdRTulAau/A==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.0.tgz",
+      "integrity": "sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw==",
       "optional": true,
       "dependencies": {
         "bare-os": "^2.1.0"
@@ -12171,9 +12157,9 @@
       }
     },
     "node_modules/minimatch": {
-      "version": "9.0.4",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
-      "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
+      "version": "9.0.3",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
       "dev": true,
       "dependencies": {
         "brace-expansion": "^2.0.1"
@@ -16518,15 +16504,15 @@
       }
     },
     "node_modules/puppeteer": {
-      "version": "22.6.3",
-      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.6.3.tgz",
-      "integrity": "sha512-KZOnthMbvr4+7cPKFeeOCJPe8DzOKGC0GbMXmZKOP/YusXQ6sqxA0vt6frstZq3rUJ277qXHlZNFf01VVwdHKw==",
+      "version": "22.6.2",
+      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.6.2.tgz",
+      "integrity": "sha512-3GMAJ9adPUSdIHGuYV1b1RqRB6D2UScjnq779uZsvpAP6HOWw2+9ezZiUZaAXVST+Ku7KWsxOjkctEvRasJClA==",
       "hasInstallScript": true,
       "dependencies": {
-        "@puppeteer/browsers": "2.2.1",
+        "@puppeteer/browsers": "2.2.0",
         "cosmiconfig": "9.0.0",
         "devtools-protocol": "0.0.1262051",
-        "puppeteer-core": "22.6.3"
+        "puppeteer-core": "22.6.2"
       },
       "bin": {
         "puppeteer": "lib/esm/puppeteer/node/cli.js"
@@ -16536,9 +16522,9 @@
       }
     },
     "node_modules/puppeteer/node_modules/@puppeteer/browsers": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.1.tgz",
-      "integrity": "sha512-QSXujx4d4ogDamQA8ckkkRieFzDgZEuZuGiey9G7CuDcbnX4iINKWxTPC5Br2AEzY9ICAvcndqgAUFMMKnS/Tw==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.0.tgz",
+      "integrity": "sha512-MC7LxpcBtdfTbzwARXIkqGZ1Osn3nnZJlm+i0+VqHl72t//Xwl9wICrXT8BwtgC6s1xJNHsxOpvzISUqe92+sw==",
       "dependencies": {
         "debug": "4.3.4",
         "extract-zip": "2.0.1",
@@ -16621,11 +16607,11 @@
       }
     },
     "node_modules/puppeteer/node_modules/puppeteer-core": {
-      "version": "22.6.3",
-      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.6.3.tgz",
-      "integrity": "sha512-YrTAak5zCTWVTnVaCK1b7FD1qFCCT9bSvQhLzamnIsJ57/tfuXiT8ZvPJR2SBfahyFTYFCcaZAd/Npow3lmDGA==",
+      "version": "22.6.2",
+      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.6.2.tgz",
+      "integrity": "sha512-Sws/9V2/7nFrn3MSsRPHn1pXJMIFn6FWHhoMFMUBXQwVvcBstRIa9yW8sFfxePzb56W1xNfSYzPRnyAd0+qRVQ==",
       "dependencies": {
-        "@puppeteer/browsers": "2.2.1",
+        "@puppeteer/browsers": "2.2.0",
         "chromium-bidi": "0.5.16",
         "debug": "4.3.4",
         "devtools-protocol": "0.0.1262051",
@@ -19125,12 +19111,12 @@
       }
     },
     "node_modules/ts-api-utils": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
-      "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
+      "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
       "dev": true,
       "engines": {
-        "node": ">=16"
+        "node": ">=16.13.0"
       },
       "peerDependencies": {
         "typescript": ">=4.2.0"
diff --git a/package.json b/package.json
index 889921573..65d20d8aa 100644
--- a/package.json
+++ b/package.json
@@ -96,12 +96,12 @@
     "@semantic-release/changelog": "^6.0.3",
     "@semantic-release/commit-analyzer": "^12.0.0",
     "@semantic-release/git": "^10.0.1",
-    "@semantic-release/github": "^10.0.3",
+    "@semantic-release/github": "^10.0.2",
     "@semantic-release/npm": "^12.0.0",
     "@semantic-release/release-notes-generator": "^13.0.0",
     "@types/jest": "^29.5.12",
-    "@typescript-eslint/eslint-plugin": "^7.6.0",
-    "@typescript-eslint/parser": "^7.6.0",
+    "@typescript-eslint/eslint-plugin": "^7.5.0",
+    "@typescript-eslint/parser": "^7.5.0",
     "chokidar-cli": "^3.0.0",
     "concurrently": "^8.2.2",
     "copyfiles": "^2.4.1",
diff --git a/src/modules/esl-utils/decorators/attr.ts b/src/modules/esl-utils/decorators/attr.ts
index 5e1ff998f..96f11d360 100644
--- a/src/modules/esl-utils/decorators/attr.ts
+++ b/src/modules/esl-utils/decorators/attr.ts
@@ -1,7 +1,8 @@
-import {identity} from '../misc/functions';
+import {identity, resolveProperty} from '../misc/functions';
 import {parseString, toKebabCase} from '../misc/format';
-import {getAttr, setAttr} from '../dom/attr';
+import {getAttr, getClosestAttr, setAttr} from '../dom/attr';
 
+import type {PropertyProvider} from '../misc/functions';
 import type {ESLAttributeDecorator} from '../dom/attr';
 import type {ESLDomElementTarget} from '../abstract/dom-target';
 
@@ -14,10 +15,21 @@ type AttrDescriptor<T = string> = {
   name?: string;
   /** Create getter only */
   readonly?: boolean;
+  /**
+   * Specifies the attribute inheritance behavior.
+   * If `inherit` is set to `true`, the attribute will inherit the value from the same-named attribute of the closest parent element in the DOM tree.
+   * For instance, `@attr({inherit: true}) ignore;` will look for an `ignore` attribute in the parent elements if it's not defined in the current element.
+   * If `dataAttr` is also true, it will search for `data-ignore` instead.
+   *
+   * If `inherit` is set to a string, it will use this string as the attribute name to search for in the parent elements.
+   * For example, `@attr({inherit: 'alt-ignore'}) ignore;` will first look for its own `ignore` attribute (or 'data-ignore' if `dataAttr` is true),
+   * and if not found, it will look for an `alt-ignore` attribute in the parent elements.
+   */
+  inherit?: boolean | string;
   /** Use data-* attribute */
   dataAttr?: boolean;
-  /** Default property value. Used if no attribute is present on the element. Empty string by default. */
-  defaultValue?: T;
+  /** Default property value. Used if no attribute is present on the element. Empty string by default. Supports provider function. */
+  defaultValue?: T | PropertyProvider<T>;
   /** Parser from attribute value */
   parser?: AttrParser<T>;
   /** Serializer to transform passed value to attribute value */
@@ -35,12 +47,14 @@ const buildAttrName =
 export const attr = <T = string>(config: AttrDescriptor<T> = {}): ESLAttributeDecorator => {
   return (target: ESLDomElementTarget, propName: string): any => {
     const attrName = buildAttrName(config.name || propName, !!config.dataAttr);
+    const inheritAttrName = typeof config.inherit === 'string' ? config.inherit : attrName;
 
     function get(): T | null {
-      const val = getAttr(this, attrName);
-      if (val === null && 'defaultValue' in config) return config.defaultValue as T;
+      const val = config.inherit ? getAttr(this, attrName) || getClosestAttr(this, inheritAttrName) : getAttr(this, attrName);
+      if (val === null && 'defaultValue' in config) return resolveProperty(config.defaultValue, this) as T;
       return (config.parser || parseString as AttrParser<any>)(val);
     }
+
     function set(value: T): void {
       setAttr(this, attrName, (config.serializer as AttrSerializer<any> || identity)(value));
     }
diff --git a/src/modules/esl-utils/dom/attr.ts b/src/modules/esl-utils/dom/attr.ts
index ab9765fdd..93c85c1d8 100644
--- a/src/modules/esl-utils/dom/attr.ts
+++ b/src/modules/esl-utils/dom/attr.ts
@@ -35,3 +35,10 @@ export function setAttr($el: ESLAttributeTarget, name: string, value: undefined
     $el.setAttribute(name, value === true ? '' : value);
   }
 }
+
+/** Gets attribute value from the closest element with group behavior settings */
+export function getClosestAttr($el: ESLAttributeTarget, attrName: string): string | null {
+  if (!($el = resolveDomTarget($el))) return null;
+  const $closest = $el.closest(`[${attrName}]`);
+  return $closest ? $closest.getAttribute(attrName) : null;
+}


Test patch:
diff --git a/e2e/package.json b/e2e/package.json
index 7d27d91fa..23216eb9b 100644
--- a/e2e/package.json
+++ b/e2e/package.json
@@ -19,7 +19,7 @@
     "@types/puppeteer": "^7.0.4",
     "jest-image-snapshot": "^6.4.0",
     "jest-puppeteer": "^10.0.1",
-    "puppeteer": "^22.6.3",
+    "puppeteer": "^22.6.2",
     "stucumber": "^0.19.0"
   }
 }
diff --git a/src/modules/esl-utils/decorators/test/attr.test.ts b/src/modules/esl-utils/decorators/test/attr.test.ts
index f44f2f865..4651b2900 100644
--- a/src/modules/esl-utils/decorators/test/attr.test.ts
+++ b/src/modules/esl-utils/decorators/test/attr.test.ts
@@ -1,5 +1,6 @@
 import '../../../../polyfills/es5-target-shim';
 import {attr} from '../attr';
+import {ESLTestTemplate} from '../../test/template';
 
 describe('Decorator: attr', () => {
 
@@ -18,6 +19,8 @@ describe('Decorator: attr', () => {
     public readonlyField: string | null;
     @attr({defaultValue: 'def'})
     public defField: string | boolean;
+    @attr({defaultValue: () => 'test-provider'})
+    public defProvider: string;
   }
   customElements.define('test-el-attr', TestElement);
   const el = new TestElement();
@@ -99,6 +102,124 @@ describe('Decorator: attr', () => {
     el.defField = false;
     expect(el.defField).toBe('def');
     expect(el.hasAttribute('def-field')).toBe(false);
+    expect(el.defProvider).toBe('test-provider');
+    el.defProvider = '';
+    expect(el.defProvider).toBe('');
+  });
+
+  describe('Inherit parameter', () => {
+
+    class ThirdElement extends HTMLElement {
+      @attr({inherit: 'box'})
+      public container: string;
+      @attr({inherit: 'parent', dataAttr: true})
+      public ignore: string;
+      @attr({inherit: true})
+      public disallow: string;
+      @attr({inherit: true, dataAttr: true})
+      public allow: string;
+    }
+    customElements.define('third-el', ThirdElement);
+
+    class SecondElement extends HTMLElement {}
+    customElements.define('second-el', SecondElement);
+
+    const SCOPE: any = {
+      firstEl: '#first-el',
+      secondEl: '#second-el',
+      thirdEl: '#third-el',
+    };
+    const TEMPLATE = ESLTestTemplate.create(`
+      <div id="first-el">
+        <second-el id="second-el">
+          <third-el id="third-el"></third-el>
+        </second-el>
+      </div>
+    `, SCOPE).bind('beforeeach');
+
+    describe('Inherit searches for the closest element with explicitly declared name', () => {
+      //  @attr({inherit: 'box'}) public container: string;
+      test('The attribute inherit the value from own same-named attribute', () => {
+        TEMPLATE.$thirdEl.setAttribute('container', 'value');
+        expect(TEMPLATE.$thirdEl.container).toBe('value');
+      });
+      test('Own attribute setter changes the own value', () => {
+        TEMPLATE.$thirdEl.container = 'container';
+        expect(TEMPLATE.$thirdEl.container).toBe('container');
+      });
+      test('The value should be resolved from the closest DOM element (custom-element)', () => {
+        TEMPLATE.$secondEl.setAttribute('box', 'carousel');
+        expect(TEMPLATE.$thirdEl.container).toBe('carousel');
+      });
+      test('The value resolves from the closest element (non-custom-element) in DOM', () => {
+        TEMPLATE.$firstEl.setAttribute('box', 'slide');
+        expect(TEMPLATE.$thirdEl.container).toBe('slide');
+      });
+      test('Elements with declared inherit are absent in DOM and returns empty string', () => {
+        expect(TEMPLATE.$thirdEl.container).toBe('');
+      });
+    });
+
+    describe('Inherit searches for the closest element with explicitly declared data attribute name', () => {
+      // @attr({inherit: 'parent', dataAttr: true}) public ignore: string;
+      test('The attribute inherit the value from the same-named data-attribute', () => {
+        TEMPLATE.$thirdEl.setAttribute('data-ignore', 'swipe');
+        expect(TEMPLATE.$thirdEl.ignore).toBe('swipe');
+      });
+      test('Own attribute setter changes the own value', () => {
+        TEMPLATE.$thirdEl.ignore = 'touch';
+        expect(TEMPLATE.$thirdEl.ignore).toBe('touch');
+      });
+      test('The value resolves from the closest element (custom-element) in DOM', () => {
+        TEMPLATE.$secondEl.setAttribute('parent', 'close');
+        expect(TEMPLATE.$thirdEl.ignore).toBe('close');
+      });
+      test('The value resolves from the closest element (non-custom-element) in DOM', () => {
+        TEMPLATE.$firstEl.setAttribute('parent', 'open');
+        expect(TEMPLATE.$thirdEl.ignore).toBe('open');
+      });
+      test('Elements with declared inherit are absent in DOM and returns empty string', () => {
+        expect(TEMPLATE.$thirdEl.ignore).toBe('');
+      });
+    });
+
+    describe('Inherit searches for the closest element with the same attribute name in DOM', () => {
+      // @attr({inherit: true}) public disallow: string;
+      test('The attribute inherit the value from the same attribute name', () => {
+        TEMPLATE.$thirdEl.disallow = 'scroll';
+        expect(TEMPLATE.$thirdEl.disallow).toBe('scroll');
+      });
+      test('The value resolves from the closest element (custom-element) in DOM with the same attribute name', () => {
+        TEMPLATE.$secondEl.setAttribute('disallow', 'activator');
+        expect(TEMPLATE.$thirdEl.disallow).toBe('activator');
+      });
+      test('The value resolves from the closest element (non-custom-element) in DOM with the same attribute name', () => {
+        TEMPLATE.$firstEl.setAttribute('disallow', 'deactivator');
+        expect(TEMPLATE.$thirdEl.disallow).toBe('deactivator');
+      });
+      test('Elements with declared inherit are absent in DOM and returns empty string', () => {
+        expect(TEMPLATE.$thirdEl.disallow).toBe('');
+      });
+    });
+
+    describe('Inherit searches for the closest element with the same data-attribute name in DOM', () => {
+      // @attr({inherit: true, dataAttr: true}) public allow: string;
+      test('The attribute inherit the value from the same attribute name', () => {
+        TEMPLATE.$thirdEl.allow = 'option';
+        expect(TEMPLATE.$thirdEl.allow).toBe('option');
+      });
+      test('The value resolves from the closest element (custom-element) in DOM with the same data-attribute name', () => {
+        TEMPLATE.$secondEl.setAttribute('data-allow', 'scroll');
+        expect(TEMPLATE.$thirdEl.allow).toBe('scroll');
+      });
+      test('The value resolves from the closest element (non-custom-element) in DOM with the same data-attribute name', () => {
+        TEMPLATE.$firstEl.setAttribute('data-allow', 'swipe');
+        expect(TEMPLATE.$thirdEl.allow).toBe('swipe');
+      });
+      test('Elements with declared inherit are absent in DOM and returns empty string', () => {
+        expect(TEMPLATE.$thirdEl.allow).toBe('');
+      });
+    });
   });
 
   afterAll(() => {
diff --git a/src/modules/esl-utils/dom/test/attr.test.ts b/src/modules/esl-utils/dom/test/attr.test.ts
index 0212148f3..47db0a9b6 100644
--- a/src/modules/esl-utils/dom/test/attr.test.ts
+++ b/src/modules/esl-utils/dom/test/attr.test.ts
@@ -1,4 +1,4 @@
-import {hasAttr, getAttr, setAttr} from '../attr';
+import {hasAttr, getAttr, setAttr, getClosestAttr} from '../attr';
 
 describe('Attribute', () => {
   const attrName = 'test-attr';
@@ -118,4 +118,28 @@ describe('Attribute', () => {
       expect($el3.getAttribute(attrName)).toBe(attrValue);
     });
   });
+
+
+  describe('getClosestAttr', () => {
+    const $el = document.createElement('div');
+    $el.setAttribute(attrName, attrValue);
+
+    const $parent = document.createElement('div');
+    const $parentName = 'parent-attr';
+    const $parentValue = 'parent-value';
+    $parent.setAttribute($parentName, $parentValue);
+
+    $parent.append($el);
+    document.body.append($parent);
+
+    test('should return attribute from the current element', () => {
+      expect(getClosestAttr($el, attrName)).toBe(attrValue);
+    });
+    test('should return an attribute from the parent DOM element', () => {
+      expect(getClosestAttr($el, $parentName)).toBe($parentValue);
+    });
+    test('should return null in case the specified attribute is absent at the current element and its parents', () => {
+      expect(getClosestAttr($el, 'name')).toBe(null);
+    });
+  });
 });