Repository: exadel-inc/esl
Pull request #401 (2021-08-19 07:43:52)

Feat/throttle promise


Patch:
diff --git a/.eslintrc.json b/.eslintrc.json
index 3152ede05..c8c84dfc4 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -7,11 +7,7 @@
   "extends": [
     "eslint:recommended",
     "plugin:import/typescript",
-    "plugin:@typescript-eslint/recommended",
-    "./eslint/codestyle.eslintrc.yml",
-    "./eslint/coderules.eslintrc.yml",
-    "./eslint/import.eslintrc.yml",
-    "./eslint/sonarjs.eslintrc.yml"
+    "plugin:@typescript-eslint/recommended"
   ],
   "parser": "@typescript-eslint/parser",
   "parserOptions": {
@@ -26,6 +22,7 @@
     "eslint-plugin-tsdoc"
   ],
   "rules": {
+    "comma-dangle": "off",
     "complexity": "warn",
     "constructor-super": "warn",
     "curly": ["warn", "multi-line"],
@@ -45,14 +42,17 @@
     "no-empty": "warn",
     "no-eval": "off",
     "no-fallthrough": "off",
+    "no-invalid-this": "off",
     "no-mixed-spaces-and-tabs": "error",
     "no-multiple-empty-lines": "off",
     "no-new-wrappers": "warn",
+    "no-shadow": ["off"],
     "no-throw-literal": "warn",
     "no-trailing-spaces": "warn",
     "no-undef-init": "warn",
     "no-underscore-dangle": "off",
     "no-unsafe-finally": "warn",
+    "no-unused-expressions": "off",
     "no-labels": "warn",
     "no-var": "error",
     "object-shorthand": "warn",
@@ -60,14 +60,85 @@
     "prefer-arrow/prefer-arrow-functions": "off",
     "prefer-const": "error",
     "radix": "warn",
+    "semi": ["error", "always"],
     "semi-style": ["error", "last"],
+    "space-before-function-paren": [
+      "warn",
+      {
+        "anonymous": "always",
+        "named": "never",
+        "asyncArrow": "always"
+      }
+    ],
     "spaced-comment": "warn",
     "use-isnan": "error",
     "valid-typeof": "error",
-    "space-in-parens": ["warn", "never"],
 
     "tsdoc/syntax": "warn",
 
+    "@typescript-eslint/consistent-type-imports": ["error", { "prefer": "type-imports" }],
+    "@typescript-eslint/object-curly-spacing": ["warn",  "never"],
+    "@typescript-eslint/explicit-function-return-type": "off",
+
+    "@typescript-eslint/adjacent-overload-signatures": "warn",
+    "@typescript-eslint/array-type": "warn",
+    "@typescript-eslint/ban-types": "warn",
+    "@typescript-eslint/ban-ts-comment": "warn",
+    "@typescript-eslint/no-inferrable-types": "off",
+    "@typescript-eslint/member-ordering": "off",
+    "@typescript-eslint/no-this-alias": "error",
+    "@typescript-eslint/no-empty-function": "off",
+    "@typescript-eslint/no-empty-interface": "off",
+    "@typescript-eslint/prefer-as-const": "error",
+    "@typescript-eslint/no-extra-semi": "error",
+    "@typescript-eslint/no-explicit-any": "off",
+    "@typescript-eslint/no-misused-new": "warn",
+    "@typescript-eslint/no-namespace": "error",
+    "@typescript-eslint/no-parameter-properties": "off",
+    "@typescript-eslint/no-unused-vars": "off",
+    "@typescript-eslint/no-use-before-define": "off",
+    "@typescript-eslint/no-var-requires": "error",
+    "@typescript-eslint/no-extra-non-null-assertion": "error",
+    "@typescript-eslint/no-non-null-assertion": "off",
+    "@typescript-eslint/no-non-null-asserted-optional-chain": "error",
+    "@typescript-eslint/prefer-for-of": "off",
+    "@typescript-eslint/prefer-function-type": "warn",
+    "@typescript-eslint/prefer-namespace-keyword": "warn",
+    "@typescript-eslint/quotes": ["error", "single"],
+    "@typescript-eslint/semi": ["error"],
+    "@typescript-eslint/triple-slash-reference": "warn",
+    "@typescript-eslint/unified-signatures": "warn",
+    "@typescript-eslint/explicit-module-boundary-types": "off",
+    "@typescript-eslint/no-for-in-array": "error",
+    "@typescript-eslint/no-unsafe-assignment": "off",
+    "@typescript-eslint/no-unnecessary-type-assertion": "warn",
+    "@typescript-eslint/no-shadow": "warn",
+
+    "import/order": ["warn", {"groups": ["builtin", "external", "parent", "sibling", "index", "object", "type"]}],
+    "import/export": "warn",
+    "import/named": "error",
+    "import/no-default-export": "warn",
+    "import/no-self-import": "error",
+
+    "sonarjs/cognitive-complexity": "error",
+    "sonarjs/max-switch-cases": ["error", 8],
+    "sonarjs/no-collapsible-if": "error",
+    "sonarjs/no-duplicated-branches": "error",
+    "sonarjs/no-gratuitous-expressions": "warn",
+    "sonarjs/no-identical-functions": "warn",
+    "sonarjs/no-inverted-boolean-check": "warn",
+    "sonarjs/no-nested-switch": "error",
+    "sonarjs/no-redundant-boolean": "error",
+    "sonarjs/no-redundant-jump": "error",
+    "sonarjs/no-same-line-conditional": "error",
+    "sonarjs/no-small-switch": "warn",
+    "sonarjs/no-unused-collection": "error",
+    "sonarjs/no-useless-catch": "error",
+    "sonarjs/prefer-single-boolean-return": "error",
+    "sonarjs/prefer-while": "error",
+    "sonarjs/prefer-object-literal": "warn",
+    "sonarjs/prefer-immediate-return": "warn",
+
     "editorconfig/charset": "warn",
     "editorconfig/eol-last": "warn",
     "editorconfig/no-trailing-spaces": "warn"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bca1c3d68..77ab8e01a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,31 +1,3 @@
-# [3.0.0-beta.19](https://github.com/exadel-inc/esl/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2021-08-19)
-
-
-### Bug Fixes
-
-* **esl-footnotes:** fix broken click on back-to-note ([e66ae96](https://github.com/exadel-inc/esl/commit/e66ae967681fc2a59e71fb5c7f990d4e16dbc6c2))
-
-# [3.0.0-beta.18](https://github.com/exadel-inc/esl/compare/v3.0.0-beta.17...v3.0.0-beta.18) (2021-08-18)
-
-
-### Bug Fixes
-
-* **esl-footnotes:** fix footnotes soting and reindex ([f13ba79](https://github.com/exadel-inc/esl/commit/f13ba79d72383584bf62ced35cda9d587697a677))
-* **esl-footnotes:** fix IE11 issue with Map.iterator absent ([3bad82b](https://github.com/exadel-inc/esl/commit/3bad82b383a0e9fcd41d3d3bb5d6452a9673e491))
-* **esl-media:** fix toggle method and process keydown event otb ([b3ad030](https://github.com/exadel-inc/esl/commit/b3ad030b42ed0e28946b73bfe5c661bd9d899d74))
-* **esl-note:** fix the issue with lost tooltip text after cloning of element ([882e0b0](https://github.com/exadel-inc/esl/commit/882e0b0398d16bff04e022ce994484bbdc917489))
-
-
-### Features
-
-* **esl-a11y-group:** add jsx tag shape ([c469f20](https://github.com/exadel-inc/esl/commit/c469f2018989fa03b44ca300e9593a04b16ab79f))
-* **esl-panel:** add jsx tag shape ([ba00085](https://github.com/exadel-inc/esl/commit/ba00085e44e8c45c9e4ae6182251e7e420857df3))
-* **esl-tabs:** add jsx tag shape ([4688984](https://github.com/exadel-inc/esl/commit/4688984cb00a0fabdc7322d1e4cc8d68b12dac28))
-* **esl-toggleable:** add jsx tag shape ([d583f24](https://github.com/exadel-inc/esl/commit/d583f243fdb68ef02c7b711ade7c7ad360a69d10))
-* **esl-trigger:** add jsx tag shape ([2b36fae](https://github.com/exadel-inc/esl/commit/2b36fae8e1d08f11eb9311098a4763e2d432788b))
-* **esl-utils:** add butch manipulations support for `CSSClassUtils` ([#395](https://github.com/exadel-inc/esl/issues/395)) ([3635e39](https://github.com/exadel-inc/esl/commit/3635e39507fd9227052580d07f1490f8dc8ac863))
-* **esl-utils:** add new syntax options support for format utility ([#393](https://github.com/exadel-inc/esl/issues/393)) ([e44aca0](https://github.com/exadel-inc/esl/commit/e44aca01b054430fe724fc896bfb9d55ea30f959))
-
 # [3.0.0-beta.17](https://github.com/exadel-inc/esl/compare/v3.0.0-beta.16...v3.0.0-beta.17) (2021-08-13)
 
 
diff --git a/eslint/coderules.eslintrc.yml b/eslint/coderules.eslintrc.yml
deleted file mode 100644
index 9a1707a32..000000000
--- a/eslint/coderules.eslintrc.yml
+++ /dev/null
@@ -1,282 +0,0 @@
-rules:
-  # === Compulsory practices ===
-
-  # Enforces consistent usage of type imports
-  '@typescript-eslint/consistent-type-imports':
-    - error
-    - prefer: type-imports
-
-  # Disallow the use of custom TypeScript modules and namespaces
-  '@typescript-eslint/no-namespace': error
-
-  # Disallows using a non-null assertion after an optional chain expression
-  '@typescript-eslint/no-non-null-asserted-optional-chain': error
-
-  # Disallows invocation of require()
-  '@typescript-eslint/no-require-imports': error
-
-  # Disallow aliasing this
-  '@typescript-eslint/no-this-alias': error
-
-  # Flags unnecessary equality comparisons against boolean literals
-  '@typescript-eslint/no-unnecessary-boolean-literal-compare': error
-
-  # Disallows the use of require statements except in import statements
-  '@typescript-eslint/no-var-requires': error
-
-  # Prefer usage of as const over literal type
-  '@typescript-eslint/prefer-as-const': error
-
-  # Disallow iterating over an array with a for-in loop
-  '@typescript-eslint/no-for-in-array': error
-
-  # Disallow extra non-null assertion
-  '@typescript-eslint/no-extra-non-null-assertion': error
-
-  # Enforce default parameters to be last
-  'default-param-last': off
-  '@typescript-eslint/default-param-last': error
-
-  # === Warnings ===
-
-  # Require that member overloads be consecutive
-  '@typescript-eslint/adjacent-overload-signatures': warn
-
-  # Requires using either T[] or Array<T> for arrays
-  '@typescript-eslint/array-type': warn
-
-  # Disallows awaiting a value that is not a Thenable
-
-  '@typescript-eslint/await-thenable': warn
-
-  # Bans @ts-<directive> comments from being used or requires descriptions after directive
-  '@typescript-eslint/ban-ts-comment': warn
-
-  # Bans specific types from being used
-  '@typescript-eslint/ban-types': warn
-
-  # Enforce valid definition of new and constructor
-  '@typescript-eslint/no-misused-new': warn
-
-  # Warns when a namespace qualifier is unnecessary
-  '@typescript-eslint/no-unnecessary-qualifier': warn
-
-  # Use function types instead of interfaces with call signatures
-  '@typescript-eslint/prefer-function-type': warn
-
-  # Sets preference level for triple slash directives versus ES6-style import declarations
-  '@typescript-eslint/triple-slash-reference': warn
-
-  # Warns for any two overloads that could be unified into one by using a union or an optional/rest parameter
-  '@typescript-eslint/unified-signatures': warn
-
-  # Warns if a type assertion does not change the type of an expression
-  '@typescript-eslint/no-unnecessary-type-assertion': warn
-
-  # === Disabled Rules ===
-
-  # Disallow the delete operator with computed key expressions
-  '@typescript-eslint/no-dynamic-delete': off
-
-  # Disallow the use of parameter properties in class constructors
-  '@typescript-eslint/no-parameter-properties': off
-
-  # Disallow the use of type aliases
-  '@typescript-eslint/no-type-alias': off
-
-  # Prefer a ‘for-of’ loop over a standard ‘for’ loop if the index is only used to access the array being iterated
-  '@typescript-eslint/prefer-for-of': off
-
-  # When adding two variables, operands must both be of type number or of type string
-  '@typescript-eslint/restrict-plus-operands': off
-
-  # Restricts the types allowed in boolean expressions
-  '@typescript-eslint/strict-boolean-expressions': off
-
-  # Disallow the declaration of empty interfaces
-  '@typescript-eslint/no-empty-interface': off
-
-  # Disallow empty functions
-  'no-empty-function': off
-  '@typescript-eslint/no-empty-function': off
-
-  # Disallow usage of the any type
-  '@typescript-eslint/no-explicit-any': off
-
-  # Disallows non-null assertions using the ! postfix operator
-  '@typescript-eslint/no-non-null-assertion': off
-
-  # Ensures that literals on classes are exposed in a consistent style
-  '@typescript-eslint/class-literal-property-style': off
-
-  # Enforce or disallow the use of the record type
-  '@typescript-eslint/consistent-indexed-object-style': off
-
-  # Consistent with type definition either interface or type
-  '@typescript-eslint/consistent-type-definitions': off
-
-  # Require explicit return types on functions and class methods
-  '@typescript-eslint/explicit-function-return-type': off
-
-  # Require explicit accessibility modifiers on class properties and methods
-  '@typescript-eslint/explicit-member-accessibility': off
-
-  # Require a consistent member declaration order
-  'member-ordering': off
-  '@typescript-eslint/member-ordering': off
-
-  # Enforces using a particular method signature syntax
-  '@typescript-eslint/method-signature-style': off
-
-  # Requires that .toString() is only called on objects which provide useful information when stringified
-  '@typescript-eslint/no-base-to-string': off
-
-  # Disallow non-null assertion in locations that may be confusing
-  '@typescript-eslint/no-confusing-non-null-assertion': off
-
-  # Requires expressions of type void to appear in statement position
-  '@typescript-eslint/no-confusing-void-expression': off
-
-  # Forbids the use of classes as namespaces
-  '@typescript-eslint/no-extraneous-class': off
-
-  # Requires Promise-like values to be handled appropriately
-  # TODO: enable
-  '@typescript-eslint/no-floating-promises': off
-
-  # Disallow usage of the implicit any type in catch clauses
-  # TODO: enable
-  '@typescript-eslint/no-implicit-any-catch': off
-
-  # Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean
-  # TODO: review
-  '@typescript-eslint/no-inferrable-types': off
-
-  # Disallows usage of void type outside of generic or return types
-  # TODO: review
-  '@typescript-eslint/no-invalid-void-type': off
-
-  # Avoid using promises in places not designed to handle them
-  # TODO: review
-  '@typescript-eslint/no-misused-promises': off
-
-  # Enforces that type arguments will not be used if not required
-  # TODO: review
-  '@typescript-eslint/no-unnecessary-type-arguments': off
-
-  # Disallows unnecessary constraints on generic types
-  # TODO: review
-  '@typescript-eslint/no-unnecessary-type-constraint': off
-
-  # Disallows calling an function with an any type value
-  # TODO: enable
-  '@typescript-eslint/no-unsafe-argument': off
-
-  # Disallows assigning any to variables and properties
-  '@typescript-eslint/no-unsafe-assignment': off
-
-  # Disallows calling an any type value
-  # TODO: enable
-  '@typescript-eslint/no-unsafe-call': off
-
-  # Disallows member access on any typed variables
-  # TODO: enable
-  '@typescript-eslint/no-unsafe-member-access': off
-
-  # Disallows returning any from a function
-  # TODO: enable
-  '@typescript-eslint/no-unsafe-return': off
-
-  # Prefers a non-null assertion over explicit type cast when possible
-  # TODO: review
-  '@typescript-eslint/non-nullable-type-assertion-style': off
-
-  # Prefer initializing each enums member value
-  # TODO: review
-  '@typescript-eslint/prefer-enum-initializers': off
-
-  # Require that all enum members be literal values to prevent unintended enum member name shadow issues
-  # TODO: review
-  '@typescript-eslint/prefer-literal-enum-member': off
-
-  # Enforce the usage of the nullish coalescing operator instead of logical chaining
-  # TODO: review
-  '@typescript-eslint/prefer-nullish-coalescing': off
-
-  # Prefer using concise optional chain expressions instead of chained logical ands
-  # TODO: review
-  '@typescript-eslint/prefer-optional-chain': off
-
-  # Requires that private members are marked as readonly if they're never modified outside of the constructor
-  # TODO: review
-  '@typescript-eslint/prefer-readonly': off
-
-  # Requires that function parameters are typed as readonly to prevent accidental mutation of inputs
-  # TODO: review
-  '@typescript-eslint/prefer-readonly-parameter-types': off
-
-  # Prefer using type parameter when calling Array#reduce instead of casting
-  # TODO: review
-  '@typescript-eslint/prefer-reduce-type-parameter': off
-
-  # Enforce that RegExp#exec is used instead of String#match if no global flag is provided
-  # TODO: review
-  '@typescript-eslint/prefer-regexp-exec': off
-
-  # Enforce that this is used when only this type is returned
-  '@typescript-eslint/prefer-return-this-type': off
-
-  # Enforce the use of String#startsWith and String#endsWith instead of other equivalent methods of checking substrings
-  # TODO: review
-  '@typescript-eslint/prefer-string-starts-ends-with': off
-
-  # Recommends using @ts-expect-error over @ts-ignore
-  # TODO: review
-  '@typescript-eslint/prefer-ts-expect-error': off
-
-  # Requires any function or method that returns a Promise to be marked async
-  # TODO: review
-  '@typescript-eslint/promise-function-async': off
-
-  # Requires Array#sort calls to always provide a compareFunction
-  # TODO: review
-  '@typescript-eslint/require-array-sort-compare': off
-
-  # Enforce template literal expressions to be of string type
-  # TODO: review
-  '@typescript-eslint/restrict-template-expressions': off
-
-  # Enforces that members of a type union/intersection are sorted alphabetically
-  # TODO: review
-  '@typescript-eslint/sort-type-union-intersection-members': off
-
-  # Exhaustiveness checking in switch with union type
-  # TODO: review
-  '@typescript-eslint/switch-exhaustiveness-check': off
-
-  # Requires type annotations to exist
-  # TODO: review
-  '@typescript-eslint/typedef': off
-
-  # Enforces unbound methods are called with their expected scope
-  # TODO: review
-  '@typescript-eslint/unbound-method': off
-
-  # Require explicit return and argument types on exported functions' and classes' public class methods
-  '@typescript-eslint/explicit-module-boundary-types': off
-
-  # Prevents conditionals where the type is always truthy or always falsy
-  '@typescript-eslint/no-unnecessary-condition': off
-
-  # Enforce includes method over indexOf method
-  '@typescript-eslint/prefer-includes': off
-
-  # Disallow generic Array constructors
-  'no-array-constructor': off
-  '@typescript-eslint/no-array-constructor': off
-
-  # Disallow the use of variables before they are defined
-  'no-use-before-define': off
-  '@typescript-eslint/no-use-before-define': off
-
-
diff --git a/eslint/codestyle.eslintrc.yml b/eslint/codestyle.eslintrc.yml
deleted file mode 100644
index d3b270122..000000000
--- a/eslint/codestyle.eslintrc.yml
+++ /dev/null
@@ -1,173 +0,0 @@
-rules:
-  # ==== Spacing | Code style ====
-
-  # Enforce consistent brace style for blocks
-  'brace-style': off
-  '@typescript-eslint/brace-style': warn
-
-  # Enforces consistent spacing before and after commas
-  'comma-dangle': off
-  '@typescript-eslint/comma-spacing': warn
-
-  # Require or disallow trailing comma
-  'comma-spacing': off
-  '@typescript-eslint/comma-dangle': off
-
-  # Enforce dot notation whenever possible
-  'dot-notation': off
-  '@typescript-eslint/dot-notation': off
-
-  # Require consistent spacing around type annotations
-  '@typescript-eslint/type-annotation-spacing': warn
-
-  # Enforces consistent usage of type assertions
-  '@typescript-eslint/consistent-type-assertions': warn
-
-  # Require a semicolon member delimiter style for interfaces and type literals
-  '@typescript-eslint/member-delimiter-style':
-    - warn
-    - multiline:
-        delimiter: 'semi'
-        requireLast: true
-      singleline:
-        delimiter: 'comma'
-        requireLast: false
-
-  # Require the use of the namespace keyword instead of the module keyword to declare custom TypeScript modules
-  '@typescript-eslint/prefer-namespace-keyword': warn
-
-  # Enforces naming conventions for everything across a codebase
-  # TODO: enable
-  '@typescript-eslint/naming-convention': off
-
-  # Require or disallow spacing between function identifiers and their invocations
-  'func-call-spacing': off
-  '@typescript-eslint/func-call-spacing':
-    - warn
-    - never
-
-  # Enforce consistent indentation
-  'indent': off
-  '@typescript-eslint/indent':
-    - warn
-    - 2
-    - ignoredNodes: [FunctionExpression, FunctionDeclaration]
-      SwitchCase: 1
-      ObjectExpression: 1
-      ImportDeclaration: 1
-      flatTernaryExpressions: false
-
-  # Require or disallow initialization in variable declarations
-  'init-declarations': off
-  '@typescript-eslint/init-declarations': off
-
-  # Enforce consistent spacing before and after keywords
-  'keyword-spacing': off
-  '@typescript-eslint/keyword-spacing': warn
-
-  # Require or disallow an empty line between class members
-  'lines-between-class-members': off
-  '@typescript-eslint/lines-between-class-members': off
-
-  # Disallow duplicate class members
-  'no-dupe-class-members': off
-  '@typescript-eslint/no-dupe-class-members': warn
-
-  # Disallow duplicate imports
-  'no-duplicate-imports': off
-  '@typescript-eslint/no-duplicate-imports': warn
-
-  # Disallow unnecessary parentheses
-  'no-extra-parens': off
-  '@typescript-eslint/no-extra-parens': off
-
-  # Disallow unnecessary semicolons
-  'no-extra-semi': off
-  '@typescript-eslint/no-extra-semi': warn
-
-  # Disallow the use of eval()-like methods
-  'no-implied-eval': off
-  '@typescript-eslint/no-implied-eval': warn
-
-  # Disallow this keywords outside of classes or class-like objects
-  'no-invalid-this': off
-  '@typescript-eslint/no-invalid-this': off
-
-  # Disallow function declarations that contain unsafe references inside loop statements
-  'no-loop-func': off
-  '@typescript-eslint/no-loop-func': warn
-
-  # Disallow literal numbers that lose precision
-  'no-loss-of-precision': off
-  '@typescript-eslint/no-loss-of-precision': warn
-
-  # Disallow magic numbers
-  # TODO: enable
-  'no-magic-numbers': off
-  '@typescript-eslint/no-magic-numbers': off
-
-  # Disallow variable redeclaration
-  'no-redeclare': off
-  '@typescript-eslint/no-redeclare': warn
-
-  # Disallow variable declarations from shadowing variables declared in the outer scope
-  'no-shadow': off
-  '@typescript-eslint/no-shadow': warn
-
-  # Disallow throwing literals as exceptions
-  'no-throw-literal': off
-  '@typescript-eslint/no-throw-literal': warn
-
-  # Disallow unused expressions
-  'no-unused-expressions': off
-  '@typescript-eslint/no-unused-expressions': off
-
-  # Disallow unused variables
-  'no-unused-vars': off
-  '@typescript-eslint/no-unused-vars':
-    - warn
-    - vars: all
-      args: none
-
-  # Disallow unnecessary constructors
-  # TODO: enable
-  'no-useless-constructor': off
-  '@typescript-eslint/no-useless-constructor': off
-
-  # Enforce the consistent use of either backticks, double, or single quotes
-  'quotes': off
-  '@typescript-eslint/quotes':
-    - error
-    - single
-
-  # Disallow async functions which have no await expression
-  'require-await': off
-  '@typescript-eslint/require-await': warn
-
-  # Enforces consistent returning of awaited values
-  'return-await': off
-  '@typescript-eslint/return-await': warn
-
-  # Require or disallow semicolons instead of ASI
-  'semi': off
-  '@typescript-eslint/semi': error
-
-  # Enforces consistent spacing before function parenthesis
-  'space-before-function-paren': off
-  '@typescript-eslint/space-before-function-paren':
-    - warn
-    - anonymous: always
-      named: never
-      asyncArrow: always
-
-  # This rule is aimed at ensuring there are spaces around infix operators.
-  'space-infix-ops': off
-  '@typescript-eslint/space-infix-ops': warn
-
-  # Enforce consistent spacing inside braces
-  'object-curly-spacing': off
-  '@typescript-eslint/object-curly-spacing':
-    - warn
-    - never
-
-
diff --git a/eslint/import.eslintrc.yml b/eslint/import.eslintrc.yml
deleted file mode 100644
index c680b8139..000000000
--- a/eslint/import.eslintrc.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-rules:
-  # Enforce a convention in module import order
-  'import/order':
-    - warn
-    - groups:
-      - builtin
-      - external
-      - parent
-      - sibling
-      - index
-      - object
-      - type
-
-  # Reports funny business with exports, like repeated exports of names or defaults.
-  'import/export': warn
-
-  # Verifies that all named imports are part of the set of named exports in the referenced module.
-  'import/named': error
-
-  # Prohibit default exports
-  'import/no-default-export': warn
-
-  # Forbid a module from importing itself
-  'import/no-self-import': error
diff --git a/eslint/sonarjs.eslintrc.yml b/eslint/sonarjs.eslintrc.yml
deleted file mode 100644
index e45516819..000000000
--- a/eslint/sonarjs.eslintrc.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-rules:
-  # Cognitive Complexity is a measure of how hard the control flow of a function is to understand.
-  # Functions with high Cognitive Complexity will be difficult to maintain.
-  'sonarjs/cognitive-complexity': error
-
-  # Limits maximum of switch cases before suggest a map
-  'sonarjs/max-switch-cases':
-    - error
-    - 6
-
-  # Merging collapsible if statements increases the code's readability.
-  'sonarjs/no-collapsible-if': error
-
-  # Having all branches in a switch or if chain with the same implementation is an error.
-  'sonarjs/no-duplicated-branches': error
-
-  # If a boolean expression doesn’t change the evaluation of the condition,
-  # then it is entirely unnecessary, and can be removed.
-  'sonarjs/no-gratuitous-expressions': warn
-
-  # Disallows identical functions
-  'sonarjs/no-identical-functions': warn
-
-  # It is needlessly complex to invert the result of a boolean comparison.
-  # The opposite comparison should be made instead.
-  'sonarjs/no-inverted-boolean-check': warn
-
-  # Disallows nested switch structures as they are difficult to understand
-  'sonarjs/no-nested-switch': error
-
-  # Redundant Boolean literals should be removed from expressions to improve readability.
-  'sonarjs/no-redundant-boolean': error
-
-  # Disallows redundant jump statements, such as return, break and continue
-  'sonarjs/no-redundant-jump': error
-
-  # Code is clearest when each statement has its own line.
-  'sonarjs/no-same-line-conditional': error
-
-  # For just one or two cases however, the code will be more readable with if statements.
-  'sonarjs/no-small-switch': warn
-
-  # This rule raises an issue when no methods are called on a collection other than those that add or remove values.
-  'sonarjs/no-unused-collection': error
-
-  # Disallows empty catch statements
-  'sonarjs/no-useless-catch': error
-
-  # Return of boolean literal statements wrapped into if-then-else ones should be simplified.
-  'sonarjs/prefer-single-boolean-return': error
-
-  # When only the condition expression is defined in a for loop, and the initialization and
-  # increment expressions are missing, a while loop should be used instead to increase readability.
-  'sonarjs/prefer-while': error
-
-  # Prefer creating a literal instead of fill the object "key by key"
-  'sonarjs/prefer-object-literal': warn
-
-  # Declaring a variable only to immediately return or throw it is a bad practice.
-  'sonarjs/prefer-immediate-return': warn
diff --git a/package-lock.json b/package-lock.json
index b547fa0fa..cf5e2b822 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "@exadel/esl",
-  "version": "3.0.0-beta.19",
+  "version": "3.0.0-beta.17",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -2255,13 +2255,13 @@
       "integrity": "sha512-bvBETO6kkqq32Yuk5CI3k0V/UCOTzhsqImJsboABsnCUA8BzawvnrgaRe51wqXQPqZkTwLFkRvhS7iSvsgp4pg=="
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "4.29.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.2.tgz",
-      "integrity": "sha512-x4EMgn4BTfVd9+Z+r+6rmWxoAzBaapt4QFqE+d8L8sUtYZYLDTK6VG/y/SMMWA5t1/BVU5Kf+20rX4PtWzUYZg==",
+      "version": "4.29.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.1.tgz",
+      "integrity": "sha512-AHqIU+SqZZgBEiWOrtN94ldR3ZUABV5dUG94j8Nms9rQnHFc8fvDOue/58K4CFz6r8OtDDc35Pw9NQPWo0Ayrw==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/experimental-utils": "4.29.2",
-        "@typescript-eslint/scope-manager": "4.29.2",
+        "@typescript-eslint/experimental-utils": "4.29.1",
+        "@typescript-eslint/scope-manager": "4.29.1",
         "debug": "^4.3.1",
         "functional-red-black-tree": "^1.0.1",
         "regexpp": "^3.1.0",
@@ -2287,28 +2287,28 @@
       }
     },
     "@typescript-eslint/experimental-utils": {
-      "version": "4.29.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.2.tgz",
-      "integrity": "sha512-P6mn4pqObhftBBPAv4GQtEK7Yos1fz/MlpT7+YjH9fTxZcALbiiPKuSIfYP/j13CeOjfq8/fr9Thr2glM9ub7A==",
+      "version": "4.29.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.1.tgz",
+      "integrity": "sha512-kl6QG6qpzZthfd2bzPNSJB2YcZpNOrP6r9jueXupcZHnL74WiuSjaft7WSu17J9+ae9zTlk0KJMXPUj0daBxMw==",
       "dev": true,
       "requires": {
         "@types/json-schema": "^7.0.7",
-        "@typescript-eslint/scope-manager": "4.29.2",
-        "@typescript-eslint/types": "4.29.2",
-        "@typescript-eslint/typescript-estree": "4.29.2",
+        "@typescript-eslint/scope-manager": "4.29.1",
+        "@typescript-eslint/types": "4.29.1",
+        "@typescript-eslint/typescript-estree": "4.29.1",
         "eslint-scope": "^5.1.1",
         "eslint-utils": "^3.0.0"
       }
     },
     "@typescript-eslint/parser": {
-      "version": "4.29.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.2.tgz",
-      "integrity": "sha512-WQ6BPf+lNuwteUuyk1jD/aHKqMQ9jrdCn7Gxt9vvBnzbpj7aWEf+aZsJ1zvTjx5zFxGCt000lsbD9tQPEL8u6g==",
+      "version": "4.29.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.1.tgz",
+      "integrity": "sha512-3fL5iN20hzX3Q4OkG7QEPFjZV2qsVGiDhEwwh+EkmE/w7oteiOvUNzmpu5eSwGJX/anCryONltJ3WDmAzAoCMg==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/scope-manager": "4.29.2",
-        "@typescript-eslint/types": "4.29.2",
-        "@typescript-eslint/typescript-estree": "4.29.2",
+        "@typescript-eslint/scope-manager": "4.29.1",
+        "@typescript-eslint/types": "4.29.1",
+        "@typescript-eslint/typescript-estree": "4.29.1",
         "debug": "^4.3.1"
       },
       "dependencies": {
@@ -2330,29 +2330,29 @@
       }
     },
     "@typescript-eslint/scope-manager": {
-      "version": "4.29.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.2.tgz",
-      "integrity": "sha512-mfHmvlQxmfkU8D55CkZO2sQOueTxLqGvzV+mG6S/6fIunDiD2ouwsAoiYCZYDDK73QCibYjIZmGhpvKwAB5BOA==",
+      "version": "4.29.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.1.tgz",
+      "integrity": "sha512-Hzv/uZOa9zrD/W5mftZa54Jd5Fed3tL6b4HeaOpwVSabJK8CJ+2MkDasnX/XK4rqP5ZTWngK1ZDeCi6EnxPQ7A==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.29.2",
-        "@typescript-eslint/visitor-keys": "4.29.2"
+        "@typescript-eslint/types": "4.29.1",
+        "@typescript-eslint/visitor-keys": "4.29.1"
       }
     },
     "@typescript-eslint/types": {
-      "version": "4.29.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.2.tgz",
-      "integrity": "sha512-K6ApnEXId+WTGxqnda8z4LhNMa/pZmbTFkDxEBLQAbhLZL50DjeY0VIDCml/0Y3FlcbqXZrABqrcKxq+n0LwzQ==",
+      "version": "4.29.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.1.tgz",
+      "integrity": "sha512-Jj2yu78IRfw4nlaLtKjVaGaxh/6FhofmQ/j8v3NXmAiKafbIqtAPnKYrf0sbGjKdj0hS316J8WhnGnErbJ4RCA==",
       "dev": true
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "4.29.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.2.tgz",
-      "integrity": "sha512-TJ0/hEnYxapYn9SGn3dCnETO0r+MjaxtlWZ2xU+EvytF0g4CqTpZL48SqSNn2hXsPolnewF30pdzR9a5Lj3DNg==",
+      "version": "4.29.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.1.tgz",
+      "integrity": "sha512-lIkkrR9E4lwZkzPiRDNq0xdC3f2iVCUjw/7WPJ4S2Sl6C3nRWkeE1YXCQ0+KsiaQRbpY16jNaokdWnm9aUIsfw==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.29.2",
-        "@typescript-eslint/visitor-keys": "4.29.2",
+        "@typescript-eslint/types": "4.29.1",
+        "@typescript-eslint/visitor-keys": "4.29.1",
         "debug": "^4.3.1",
         "globby": "^11.0.3",
         "is-glob": "^4.0.1",
@@ -2378,12 +2378,12 @@
       }
     },
     "@typescript-eslint/visitor-keys": {
-      "version": "4.29.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.2.tgz",
-      "integrity": "sha512-bDgJLQ86oWHJoZ1ai4TZdgXzJxsea3Ee9u9wsTAvjChdj2WLcVsgWYAPeY7RQMn16tKrlQaBnpKv7KBfs4EQag==",
+      "version": "4.29.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.1.tgz",
+      "integrity": "sha512-zLqtjMoXvgdZY/PG6gqA73V8BjqPs4af1v2kiiETBObp+uC6gRYnJLmJHxC0QyUrrHDLJPIWNYxoBV3wbcRlag==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "4.29.2",
+        "@typescript-eslint/types": "4.29.1",
         "eslint-visitor-keys": "^2.0.0"
       }
     },
@@ -2561,9 +2561,9 @@
       }
     },
     "@webpack-cli/serve": {
-      "version": "1.5.2",
-      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.2.tgz",
-      "integrity": "sha512-vgJ5OLWadI8aKjDlOH3rb+dYyPd2GTZuQC/Tihjct6F9GpXGZINo3Y/IVuZVTM1eDQB+/AOsjPUWH/WySDaXvw==",
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.1.tgz",
+      "integrity": "sha512-4vSVUiOPJLmr45S8rMGy7WDvpWxfFxfP/Qx/cxZFCfvoypTYpPPL1X8VIZMe0WTA+Jr7blUxwUSEZNkjoMTgSw==",
       "dev": true
     },
     "@xtuc/ieee754": {
@@ -8415,6 +8415,28 @@
         "picomatch": "^2.2.3"
       },
       "dependencies": {
+        "@jest/types": {
+          "version": "27.0.6",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz",
+          "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==",
+          "dev": true,
+          "requires": {
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^16.0.0",
+            "chalk": "^4.0.0"
+          }
+        },
+        "@types/yargs": {
+          "version": "16.0.4",
+          "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
+          "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==",
+          "dev": true,
+          "requires": {
+            "@types/yargs-parser": "*"
+          }
+        },
         "picomatch": {
           "version": "2.3.0",
           "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
@@ -9073,6 +9095,12 @@
       "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=",
       "dev": true
     },
+    "lodash.toarray": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
+      "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=",
+      "dev": true
+    },
     "lodash.truncate": {
       "version": "4.4.2",
       "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -9239,9 +9267,9 @@
       }
     },
     "marked": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-3.0.0.tgz",
-      "integrity": "sha512-IF2MYfFafPsLIhzLTu63secRBwOmIY+vwS+ei6qg8F+bTS+MxH6ONYRmuseGdZqF44qvoi3nP/rlpClBdgLbiQ==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.0.tgz",
+      "integrity": "sha512-KSdOTs1I/+hrQrFB+e7O/r+AorwdD4XzAi9caoRrbbkRLUS6txr1MZCZQhimm1N5Pg7A/WazC9VrYgqnwGiXMg==",
       "dev": true
     },
     "marked-terminal": {
@@ -9615,12 +9643,12 @@
       }
     },
     "node-emoji": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
-      "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==",
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
+      "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==",
       "dev": true,
       "requires": {
-        "lodash": "^4.17.21"
+        "lodash.toarray": "^4.4.0"
       }
     },
     "node-fetch": {
@@ -13258,9 +13286,9 @@
       }
     },
     "rechoir": {
-      "version": "0.7.1",
-      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
-      "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz",
+      "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==",
       "dev": true,
       "requires": {
         "resolve": "^1.9.0"
@@ -13635,9 +13663,9 @@
       }
     },
     "semantic-release": {
-      "version": "17.4.5",
-      "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.4.5.tgz",
-      "integrity": "sha512-s9JqU46nK1TQla37+kA7aSoNWDCkQq9/T5K2QX/z7bfI+zW3o1Pg/2nlZuZffnnROnt5sT0ysE49yhedINTtTw==",
+      "version": "17.4.4",
+      "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.4.4.tgz",
+      "integrity": "sha512-fQIA0lw2Sy/9+TcoM/BxyzKCSwdUd8EPRwGoOuBLgxKigPCY6kaKs8TOsgUVy6QrlTYwni2yzbMb5Q2107P9eA==",
       "dev": true,
       "requires": {
         "@semantic-release/commit-analyzer": "^8.0.0",
@@ -13657,7 +13685,7 @@
         "hook-std": "^2.0.0",
         "hosted-git-info": "^4.0.0",
         "lodash": "^4.17.21",
-        "marked": "^3.0.0",
+        "marked": "^2.0.0",
         "marked-terminal": "^4.1.1",
         "micromatch": "^4.0.2",
         "p-each-series": "^2.1.0",
@@ -13671,9 +13699,9 @@
       },
       "dependencies": {
         "debug": {
-          "version": "4.3.2",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
-          "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+          "version": "4.3.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
           "dev": true,
           "requires": {
             "ms": "2.1.2"
@@ -15133,19 +15161,32 @@
       "dev": true
     },
     "ts-jest": {
-      "version": "27.0.5",
-      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.5.tgz",
-      "integrity": "sha512-lIJApzfTaSSbtlksfFNHkWOzLJuuSm4faFAfo5kvzOiRAuoN4/eKxVJ2zEAho8aecE04qX6K1pAzfH5QHL1/8w==",
+      "version": "27.0.4",
+      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.4.tgz",
+      "integrity": "sha512-c4E1ECy9Xz2WGfTMyHbSaArlIva7Wi2p43QOMmCqjSSjHP06KXv+aT+eSY+yZMuqsMi3k7pyGsGj2q5oSl5WfQ==",
       "dev": true,
       "requires": {
         "bs-logger": "0.x",
+        "buffer-from": "1.x",
         "fast-json-stable-stringify": "2.x",
         "jest-util": "^27.0.0",
         "json5": "2.x",
         "lodash": "4.x",
         "make-error": "1.x",
+        "mkdirp": "1.x",
         "semver": "7.x",
         "yargs-parser": "20.x"
+      },
+      "dependencies": {
+        "json5": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
+          "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
+          "dev": true,
+          "requires": {
+            "minimist": "^1.2.5"
+          }
+        }
       }
     },
     "ts-loader": {
@@ -15537,15 +15578,15 @@
       }
     },
     "webpack-cli": {
-      "version": "4.8.0",
-      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.8.0.tgz",
-      "integrity": "sha512-+iBSWsX16uVna5aAYN6/wjhJy1q/GKk4KjKvfg90/6hykCTSgozbfz5iRgDTSJt/LgSbYxdBX3KBHeobIs+ZEw==",
+      "version": "4.7.2",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.2.tgz",
+      "integrity": "sha512-mEoLmnmOIZQNiRl0ebnjzQ74Hk0iKS5SiEEnpq3dRezoyR3yPaeQZCMCe+db4524pj1Pd5ghZXjT41KLzIhSLw==",
       "dev": true,
       "requires": {
         "@discoveryjs/json-ext": "^0.5.0",
         "@webpack-cli/configtest": "^1.0.4",
         "@webpack-cli/info": "^1.3.0",
-        "@webpack-cli/serve": "^1.5.2",
+        "@webpack-cli/serve": "^1.5.1",
         "colorette": "^1.2.1",
         "commander": "^7.0.0",
         "execa": "^5.0.0",
diff --git a/package.json b/package.json
index 7ba7da323..a66cd79d3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@exadel/esl",
-  "version": "3.0.0-beta.19",
+  "version": "3.0.0-beta.17",
   "private": false,
   "description": "Exadel Smart Library (ESL) - is the lightweight custom elements library that provide a set of super-flexible components",
   "license": "MIT",
@@ -84,8 +84,8 @@
     "@semantic-release/release-notes-generator": "^9.0.3",
     "@types/jest": "^27.0.1",
     "@types/smoothscroll-polyfill": "^0.3.1",
-    "@typescript-eslint/eslint-plugin": "^4.29.2",
-    "@typescript-eslint/parser": "^4.29.2",
+    "@typescript-eslint/eslint-plugin": "^4.29.1",
+    "@typescript-eslint/parser": "^4.29.1",
     "@webcomponents/custom-elements": "1.4.3",
     "@webcomponents/webcomponents-platform": "1.0.1",
     "browser-sync": "^2.27.5",
@@ -109,14 +109,14 @@
     "postcss": "^8.3.6",
     "promise-polyfill": "^8.2.0",
     "rimraf": "^3.0.2",
-    "semantic-release": "^17.4.5",
+    "semantic-release": "^17.4.4",
     "smoothscroll-polyfill": "^0.4.4",
     "stylelint": "^13.13.1",
-    "ts-jest": "^27.0.5",
+    "ts-jest": "^27.0.4",
     "ts-loader": "^9.2.5",
     "typescript": "4.3.5",
     "webpack": "^5.50.0",
-    "webpack-cli": "^4.8.0"
+    "webpack-cli": "^4.7.2"
   },
   "browserslist": [
     "last 3 versions",
diff --git a/pages/views/basic/esl-media.njk b/pages/views/basic/esl-media.njk
index ce5572b05..0eedff2ed 100644
--- a/pages/views/basic/esl-media.njk
+++ b/pages/views/basic/esl-media.njk
@@ -22,7 +22,7 @@ tags: basic
     </div>
     <div class="demo col-md-6 order-md-1">
       <div class="img-container img-container-16-9 img-container-loaded" style="border: solid black 1px;">
-        <esl-media group="demo-media" controls tabindex="0"></esl-media>
+        <esl-media group="demo-media" controls></esl-media>
       </div>
       <test-media-controls target="[data-demo='0'] esl-media"></test-media-controls>
     </div>
@@ -44,8 +44,7 @@ tags: basic
                    load-cls-declined="hide-video"
                    ready-class="video-ready"
                    ready-class-target="::parent"
-                   controls
-                   tabindex="0">
+                   controls>
         </esl-media>
       </div>
     </div>
@@ -67,8 +66,7 @@ tags: basic
                    load-cls-target="::parent(section)"
                    load-cls-accepted="show-video"
                    load-cls-declined="hide-video"
-                   controls
-                   tabindex="0">
+                   controls>
         </esl-media>
       </div>
     </div>
@@ -86,8 +84,7 @@ tags: basic
       <hr/>
       <div class="img-container img-container-16-9 img-container-loaded">
         <esl-media media-type="iframe"
-                   media-src="https://player.vimeo.com/video/1084537"
-                   tabindex="0">
+                   media-src="https://player.vimeo.com/video/1084537">
         </esl-media>
       </div>
     </div>
@@ -104,8 +101,7 @@ tags: basic
       <esl-media group="demo-media"
                  controls
                  media-type="audio"
-                 media-src="https://html5book.ru/examples/media/track.mp3"
-                 tabindex="0">
+                 media-src="https://html5book.ru/examples/media/track.mp3">
       </esl-media>
     </div>
     <div class="row btn-group-centered">
diff --git a/src/modules/draft/esl-carousel/core/view/esl-multi-carousel-view.ts b/src/modules/draft/esl-carousel/core/view/esl-multi-carousel-view.ts
index b8cc3cf15..1abdf30c4 100644
--- a/src/modules/draft/esl-carousel/core/view/esl-multi-carousel-view.ts
+++ b/src/modules/draft/esl-carousel/core/view/esl-multi-carousel-view.ts
@@ -3,7 +3,6 @@ import {ESLCarouselView, ESLCarouselViewRegistry} from './esl-carousel-view';
 import type {ESLCarousel} from '../esl-carousel';
 
 class ESLMultiCarouselView extends ESLCarouselView {
-
   constructor(carousel: ESLCarousel) {
     super(carousel);
   }
diff --git a/src/modules/esl-a11y-group/core.ts b/src/modules/esl-a11y-group/core.ts
index 94732e884..867f10f27 100644
--- a/src/modules/esl-a11y-group/core.ts
+++ b/src/modules/esl-a11y-group/core.ts
@@ -1,3 +1,1 @@
-export type {ESLA11yGroupShape} from './core/esl-a11y-group.shape';
-
 export * from './core/esl-a11y-group';
diff --git a/src/modules/esl-a11y-group/core/esl-a11y-group.shape.ts b/src/modules/esl-a11y-group/core/esl-a11y-group.shape.ts
deleted file mode 100644
index 7fa86aab4..000000000
--- a/src/modules/esl-a11y-group/core/esl-a11y-group.shape.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Tag declaration interface of {@link ESLA11yGroup} element
- * Used for JSX declaration
- */
-export interface ESLA11yGroupShape {
-  /** Define target elements multiple selector ({@link TraversingQuery} syntax) */
-  'targets'?: string;
-
-  /** Enable activation target (via click event) on selection */
-  'activate-selected'?: boolean;
-
-  /** Allowed children */
-  children: any[];
-}
diff --git a/src/modules/esl-footnotes/core/esl-footnotes-data.ts b/src/modules/esl-footnotes/core/esl-footnotes-data.ts
index 4b0ef4027..54d71a015 100644
--- a/src/modules/esl-footnotes/core/esl-footnotes-data.ts
+++ b/src/modules/esl-footnotes/core/esl-footnotes-data.ts
@@ -24,16 +24,9 @@ export function compileFootnotesGroupedList(notes: ESLNote[]): FootnotesItem[] {
   convertNotesToFootnotesList(notes).forEach(({index, text}) => {
     map.set(text, map.has(text) ? `${map.get(text)}, ${index}` : index);
   });
-  const groupedList: FootnotesItem[] = [];
-  map.forEach((index, text) => groupedList.push({index, text}));
-  return groupedList;
-}
-
-/* Sort notes list */
-export function sortFootnotes(notes: ESLNote[]): ESLNote[] {
-  return notes.sort((note1: ESLNote, note2: ESLNote) => {
-    const rect1 = note1.getBoundingClientRect();
-    const rect2 = note2.getBoundingClientRect();
-    return rect1.top - rect2.top || rect1.left - rect2.left;
-  });
+  return Array.from(map)
+    .reduce(
+      (list,[text, index]) => [...list, {index, text}],
+      []
+    );
 }
diff --git a/src/modules/esl-footnotes/core/esl-footnotes.ts b/src/modules/esl-footnotes/core/esl-footnotes.ts
index c3bca37aa..a9ca8109e 100644
--- a/src/modules/esl-footnotes/core/esl-footnotes.ts
+++ b/src/modules/esl-footnotes/core/esl-footnotes.ts
@@ -4,8 +4,7 @@ import {memoize} from '../../esl-utils/decorators/memoize';
 import {ESLBaseElement, attr} from '../../esl-base-element/core';
 import {TraversingQuery} from '../../esl-traversing-query/core';
 import {EventUtils} from '../../esl-utils/dom/events';
-import {sequentialUID} from '../../esl-utils/misc/uid';
-import {compileFootnotesGroupedList, compileFootnotesNongroupedList, sortFootnotes} from './esl-footnotes-data';
+import {compileFootnotesGroupedList, compileFootnotesNongroupedList} from './esl-footnotes-data';
 
 import type {ESLNote} from './esl-note';
 import type {FootnotesItem} from './esl-footnotes-data';
@@ -29,17 +28,11 @@ export class ESLFootnotes extends ESLBaseElement {
   }
 
   protected get footnotesList(): FootnotesItem[] {
-    this.reindex();
     return this.grouping !== 'enable'
       ? compileFootnotesNongroupedList(this._notes)
       : compileFootnotesGroupedList(this._notes);
   }
 
-  public reindex() {
-    this._notes = sortFootnotes(this._notes);
-    this._notes.forEach((note, index) => note.setIndex(index + 1));
-  }
-
   protected connectedCallback() {
     super.connectedCallback();
 
@@ -69,9 +62,7 @@ export class ESLFootnotes extends ESLBaseElement {
   }
 
   public linkNote(note: ESLNote) {
-    if (this._notes.includes(note)) return;
-    this._notes.push(note);
-    const index = +sequentialUID(ESLFootnotes.is, '');
+    const index = this._notes.push(note);
     note.link(this, index);
   }
 
@@ -119,7 +110,7 @@ export class ESLFootnotes extends ESLBaseElement {
   protected _onClick(e: MouseEvent | KeyboardEvent) {
     const target = e.target as HTMLElement;
     if (target && target.classList.contains('esl-footnotes-back-to-note')) {
-      const orderAttr = target.closest('.esl-footnotes-item')?.getAttribute('data-order');
+      const orderAttr = target.parentElement?.getAttribute('data-order');
       const order = orderAttr?.split(',').map((item) => +item);
       order && this._onBackToNote(order);
     }
diff --git a/src/modules/esl-footnotes/core/esl-note.ts b/src/modules/esl-footnotes/core/esl-note.ts
index c42338c52..7f4d2a636 100644
--- a/src/modules/esl-footnotes/core/esl-note.ts
+++ b/src/modules/esl-footnotes/core/esl-note.ts
@@ -22,9 +22,6 @@ export class ESLNote extends ESLBaseElement {
   /** Tooltip state marker */
   @boolAttr() public tooltipShown: boolean;
 
-  /** Tooltip content */
-  @attr() public html: string;
-
   /** Click event tracking media query. Default: `all` */
   @attr({defaultValue: 'all'}) public trackClick: string;
   /** Hover event tracking media query. Default: `all` */
@@ -32,6 +29,7 @@ export class ESLNote extends ESLBaseElement {
 
   protected _$footnotes: ESLFootnotes | null;
   protected _index: number;
+  protected _innerHTML: string;
 
   /** Marker to allow track hover */
   public get allowHover() {
@@ -50,21 +48,23 @@ export class ESLNote extends ESLBaseElement {
     return this._index;
   }
 
+  get html() {
+    return this._innerHTML;
+  }
+
   @ready
   protected connectedCallback() {
-    if (!this.html) {
-      this.html = this.innerHTML;
-    }
+    this._innerHTML = this.innerHTML;
     super.connectedCallback();
     this.bindEvents();
     this._sendResponseToFootnote();
   }
 
+  @ready
   protected disconnectedCallback() {
     super.disconnectedCallback();
     this.unbindEvents();
     this._$footnotes?.unlinkNote(this);
-    this.restore();
   }
 
   protected attributeChangedCallback(attrName: string, oldVal: string, newVal: string) {
@@ -100,25 +100,17 @@ export class ESLNote extends ESLBaseElement {
   public link(footnotes: ESLFootnotes, index: number) {
     this.linked = true;
     this._$footnotes = footnotes;
-    this.setIndex(index);
-    this.tabIndex = 0;
-  }
-
-  public unlink() {
-    this.restore();
-    this._sendResponseToFootnote();
-  }
-
-  public setIndex(index: number) {
     this._index = index;
     this.innerHTML = `${index}`;
+    this.tabIndex = 0;
   }
 
-  protected restore() {
+  public unlink() {
     this.linked = false;
     this._$footnotes = null;
     this.innerHTML = this.html;
     this.tabIndex = -1;
+    this._sendResponseToFootnote();
   }
 
   /** Merge params to pass to the toggleable */
diff --git a/src/modules/esl-forms/esl-select/core/esl-select-dropdown.ts b/src/modules/esl-forms/esl-select/core/esl-select-dropdown.ts
index 44bb4b7b0..682250171 100644
--- a/src/modules/esl-forms/esl-select/core/esl-select-dropdown.ts
+++ b/src/modules/esl-forms/esl-select/core/esl-select-dropdown.ts
@@ -68,7 +68,7 @@ export class ESLSelectDropdown extends ESLToggleable {
 
     super.onShow(params);
     const focusable = this.querySelector('[tabindex]') as HTMLElement;
-    focusable && focusable.focus({preventScroll: true});
+    focusable && focusable.focus( {preventScroll: true} );
     this.updatePosition();
   }
   protected onHide(params: ToggleableActionParams) {
diff --git a/src/modules/esl-image/core.ts b/src/modules/esl-image/core.ts
index b26ad7a4d..1d774cba0 100644
--- a/src/modules/esl-image/core.ts
+++ b/src/modules/esl-image/core.ts
@@ -1,3 +1,2 @@
 export type {ESLImageTagShape} from './core/esl-image.shape';
-
 export * from './core/esl-image';
diff --git a/src/modules/esl-media-query/core/conditions/media-query-base.ts b/src/modules/esl-media-query/core/conditions/media-query-base.ts
index 770f9e018..38c1eb730 100644
--- a/src/modules/esl-media-query/core/conditions/media-query-base.ts
+++ b/src/modules/esl-media-query/core/conditions/media-query-base.ts
@@ -26,13 +26,9 @@ class MediaQueryConstCondition implements IMediaQueryCondition {
   public addListener(cb: VoidFunction) {}
   public removeListener(cb: VoidFunction) {}
 
-  public optimize() {
-    return this;
-  }
+  public optimize() { return this; }
 
-  public toString() {
-    return this._matches ? 'all' : 'not all';
-  }
+  public toString() { return this._matches ? 'all' : 'not all'; }
 
   /** Compare const media condition with the passed query instance or string */
   public eq(val: IMediaQueryCondition | string): boolean {
diff --git a/src/modules/esl-media-query/core/conditions/media-query-containers.ts b/src/modules/esl-media-query/core/conditions/media-query-containers.ts
index e0222cefa..3e7f6517f 100644
--- a/src/modules/esl-media-query/core/conditions/media-query-containers.ts
+++ b/src/modules/esl-media-query/core/conditions/media-query-containers.ts
@@ -29,14 +29,10 @@ class MediaQueryContainer extends Observable<(matches: boolean) => void> impleme
     this.items.forEach((item) => item.removeListener(this._onChildChange));
   }
 
-  public get matches() {
-    return false;
-  }
+  public get matches() { return false; }
 
   /** Exclude const conditions. Unwrap empty or trivial (with one item) containers */
-  public optimize(): IMediaQueryCondition {
-    return this;
-  }
+  public optimize(): IMediaQueryCondition { return this; }
 
   /** Handle query change and dispatch it on top level in case result value is changed */
   protected _onChildChange() {
diff --git a/src/modules/esl-media/core.ts b/src/modules/esl-media/core.ts
index 6e0b1de77..d6779d77e 100644
--- a/src/modules/esl-media/core.ts
+++ b/src/modules/esl-media/core.ts
@@ -1,5 +1,4 @@
 export type {ESLMediaTagShape} from './core/esl-media.shape';
-
 export * from './core/esl-media';
 export * from './core/esl-media-provider';
 export * from './core/esl-media-registry';
diff --git a/src/modules/esl-media/core/esl-media-provider.ts b/src/modules/esl-media/core/esl-media-provider.ts
index 173a30f62..45ffc1bfa 100644
--- a/src/modules/esl-media/core/esl-media-provider.ts
+++ b/src/modules/esl-media/core/esl-media-provider.ts
@@ -125,7 +125,7 @@ export abstract class BaseProvider {
    * If the player is PAUSED then it starts playing otherwise it pause playing
    */
   protected toggle() {
-    if ([PlayerStates.PAUSED, PlayerStates.UNSTARTED, PlayerStates.VIDEO_CUED].includes(this.state)) {
+    if (this.state === PlayerStates.PAUSED) {
       return this.play();
     } else {
       return this.pause();
diff --git a/src/modules/esl-media/core/esl-media.ts b/src/modules/esl-media/core/esl-media.ts
index b3ccefe66..8ba7f0363 100644
--- a/src/modules/esl-media/core/esl-media.ts
+++ b/src/modules/esl-media/core/esl-media.ts
@@ -10,7 +10,6 @@ import {parseAspectRatio} from '../../esl-utils/misc/format';
 import {ESLMediaQuery} from '../../esl-media-query/core';
 import {TraversingQuery} from '../../esl-traversing-query/core';
 
-import {SPACE, PAUSE} from '../../esl-utils/dom/keys';
 import {getIObserver} from './esl-media-iobserver';
 import {PlayerStates} from './esl-media-provider';
 import {ESLMediaProviderRegistry} from './esl-media-registry';
@@ -124,14 +123,28 @@ export class ESLMedia extends ESLBaseElement {
       this.setAttribute('role', 'application');
     }
     this.innerHTML += '<!-- Inner Content, do not modify it manually -->';
-    this.bindEvents();
+    ESLMediaProviderRegistry.instance.addListener(this._onRegistryStateChange);
+    if (this.conditionQuery) {
+      this.conditionQuery.addListener(this.deferredReinitialize);
+    }
+    if (this.fillModeEnabled) {
+      window.addEventListener('resize', this.deferredResize);
+    }
+    window.addEventListener('esl:refresh', this._onRefresh);
     this.attachViewportConstraint();
     this.deferredReinitialize();
   }
 
   protected disconnectedCallback() {
     super.disconnectedCallback();
-    this.unbindEvents();
+    ESLMediaProviderRegistry.instance.removeListener(this._onRegistryStateChange);
+    if (this.conditionQuery) {
+      this.conditionQuery.removeListener(this.deferredReinitialize);
+    }
+    if (this.fillModeEnabled) {
+      window.removeEventListener('resize', this.deferredResize);
+    }
+    window.removeEventListener('esl:refresh', this._onRefresh);
     this.detachViewportConstraint();
     this._provider && this._provider.unbind();
   }
@@ -162,29 +175,6 @@ export class ESLMedia extends ESLBaseElement {
     }
   }
 
-  protected bindEvents() {
-    ESLMediaProviderRegistry.instance.addListener(this._onRegistryStateChange);
-    if (this.conditionQuery) {
-      this.conditionQuery.addListener(this.deferredReinitialize);
-    }
-    if (this.fillModeEnabled) {
-      window.addEventListener('resize', this.deferredResize);
-    }
-    window.addEventListener('esl:refresh', this._onRefresh);
-    this.addEventListener('keydown', this._onKeydown);
-  }
-  protected unbindEvents() {
-    ESLMediaProviderRegistry.instance.removeListener(this._onRegistryStateChange);
-    if (this.conditionQuery) {
-      this.conditionQuery.removeListener(this.deferredReinitialize);
-    }
-    if (this.fillModeEnabled) {
-      window.removeEventListener('resize', this.deferredResize);
-    }
-    window.removeEventListener('esl:refresh', this._onRefresh);
-    this.removeEventListener('keydown', this._onKeydown);
-  }
-
   public canActivate() {
     if (this.disabled) return false;
     if (this.conditionQuery) return this.conditionQuery.matches;
@@ -252,8 +242,8 @@ export class ESLMedia extends ESLBaseElement {
     return this._provider && this._provider.safeToggle();
   }
 
-  /** Focus inner player **/
-  public focusPlayer(): void {
+  /** @override */
+  public focus(): void {
     this._provider && this._provider.focus();
   }
 
@@ -331,16 +321,6 @@ export class ESLMedia extends ESLBaseElement {
     }
   }
 
-  @bind
-  protected _onKeydown(e: KeyboardEvent) {
-    if (e.target !== this) return;
-    if ([SPACE, PAUSE].includes(e.key)) {
-      e.preventDefault();
-      e.stopPropagation();
-      this.toggle();
-    }
-  }
-
   /** Update ready class state */
   protected updateReadyClass() {
     const target = TraversingQuery.first(this.readyClassTarget, this) as HTMLElement;
diff --git a/src/modules/esl-media/providers/youtube-provider.ts b/src/modules/esl-media/providers/youtube-provider.ts
index 9664f859c..816407a4c 100644
--- a/src/modules/esl-media/providers/youtube-provider.ts
+++ b/src/modules/esl-media/providers/youtube-provider.ts
@@ -103,7 +103,7 @@ export class YouTubeProvider extends BaseProvider {
   protected onPlayerReady() {
     console.debug('[ESL]: Media Youtube Player ready ', this);
     this._el = this._api.getIframe();
-    if (this.config.muted) {
+      if (this.config.muted) {
       this._api.mute();
     }
     this.component._onReady();
@@ -188,7 +188,7 @@ export class YouTubeProvider extends BaseProvider {
 // typings
 declare global {
   interface YT extends Promise<void> {
-    Player: YT.Player;
+    Player: YT.Player,
   }
 
   interface Window {
diff --git a/src/modules/esl-panel/core.ts b/src/modules/esl-panel/core.ts
index 454422dfc..79f5311f0 100644
--- a/src/modules/esl-panel/core.ts
+++ b/src/modules/esl-panel/core.ts
@@ -1,5 +1,2 @@
-export type {ESLPanelShape} from './core/esl-panel.shape';
-export type {ESLPanelGroupShape} from './core/esl-panel-group.shape';
-
 export * from './core/esl-panel';
 export * from './core/esl-panel-group';
diff --git a/src/modules/esl-panel/core/esl-panel-group.shape.ts b/src/modules/esl-panel/core/esl-panel-group.shape.ts
deleted file mode 100644
index 033676ac5..000000000
--- a/src/modules/esl-panel/core/esl-panel-group.shape.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Tag declaration interface of {@link ESLPanelGroup} element
- * Used for JSX declaration
- */
-export interface ESLPanelGroupShape {
-  /**
-   * Define rendering mode of the component (takes values from the list of supported modes; 'accordion' by default)
-   * Supported values: `accordion|tabs|open`
-   */
-  'mode'?: string;
-
-  /** Define element {@link TraversingQuery} selector to add class that identifies the rendering mode (ESLPanelGroup itself by default) */
-  'mode-cls-target'?: string;
-
-  /** Define class(es) to be added during animation ('animate' by default) */
-  'animation-class'?: string;
-
-  /** Define time to clear animation common params (max-height style + classes) ('auto' by default) */
-  'fallback-duration'?: string | number;
-
-  /** Define a list of comma-separated "modes" to disable collapse/expand animation (for both Group and Panel animations)*/
-  'no-collapse'?: string;
-
-  /** Allowed children */
-  children: any[];
-}
diff --git a/src/modules/esl-panel/core/esl-panel.shape.ts b/src/modules/esl-panel/core/esl-panel.shape.ts
deleted file mode 100644
index dc2d03c49..000000000
--- a/src/modules/esl-panel/core/esl-panel.shape.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import type {ESLToggleableShape} from '../../esl-toggleable/core/esl-toggleable.shape';
-
-/**
- * Tag declaration interface of {@link ESLPanel} element
- * Used for JSX declaration
- */
-export interface ESLPanelShape extends ESLToggleableShape {
-  /** Define class(es) to be added for active state ('open' by default) */
-  'active-class'?: string;
-  /** Define class(es) to be added during animation ('animate' by default) */
-  'animate-class'?: string;
-  /** Define class(es) to be added during animation after next render ('post-animate' by default) */
-  'post-animate-class'?: string;
-
-  /** Define time to clear animation common params (max-height style + classes) ('auto' by default) */
-  'fallback-duration'?: string | number;
-}
diff --git a/src/modules/esl-popup/core/esl-popup-position.ts b/src/modules/esl-popup/core/esl-popup-position.ts
index 66e06f1de..e85dfc789 100644
--- a/src/modules/esl-popup/core/esl-popup-position.ts
+++ b/src/modules/esl-popup/core/esl-popup-position.ts
@@ -23,7 +23,7 @@ export interface IntersectionRatioRect {
 export interface PopupPositionConfig {
   position: PositionType;
   behavior: string;
-  intersectionRatio: IntersectionRatioRect;
+  intersectionRatio: IntersectionRatioRect,
   element: DOMRect;
   inner: Rect;
   outer: Rect;
diff --git a/src/modules/esl-popup/core/esl-popup.ts b/src/modules/esl-popup/core/esl-popup.ts
index 4c0284ce9..70f402022 100644
--- a/src/modules/esl-popup/core/esl-popup.ts
+++ b/src/modules/esl-popup/core/esl-popup.ts
@@ -148,7 +148,7 @@ export class ESLPopup extends ESLToggleable {
 
     const options = {
       rootMargin: '0px',
-      threshold: [...Array(9).keys()].map((x) => x / 8)
+      threshold: [...Array(9).keys()].map((x) => x/8)
     } as IntersectionObserverInit;
 
     const observer = new IntersectionObserver(this.onActivatorIntersection, options);
diff --git a/src/modules/esl-tab/core.ts b/src/modules/esl-tab/core.ts
index 13594e87f..0b2188ea8 100644
--- a/src/modules/esl-tab/core.ts
+++ b/src/modules/esl-tab/core.ts
@@ -1,5 +1,2 @@
-export type {ESLTabShape} from './core/esl-tab.shape';
-export type {ESLTabsShape} from './core/esl-tabs.shape';
-
 export * from './core/esl-tab';
 export * from './core/esl-tabs';
diff --git a/src/modules/esl-tab/core/esl-tab.shape.ts b/src/modules/esl-tab/core/esl-tab.shape.ts
deleted file mode 100644
index 0f34a8095..000000000
--- a/src/modules/esl-tab/core/esl-tab.shape.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type {ESLTriggerShape} from '../../esl-trigger/core/esl-trigger.shape';
-
-/**
- * Tag declaration interface of {@link ESLTab} element
- * Used for JSX declaration
- */
-export interface ESLTabShape extends ESLTriggerShape {
-}
diff --git a/src/modules/esl-tab/core/esl-tabs.shape.ts b/src/modules/esl-tab/core/esl-tabs.shape.ts
deleted file mode 100644
index 83c8254d7..000000000
--- a/src/modules/esl-tab/core/esl-tabs.shape.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Tag declaration interface of {@link ESLTabs} element
- * Used for JSX declaration
- */
-export interface ESLTabsShape {
-  /**
-   * Defines scrollable mode.
-   * Supported types for different breakpoints ('disabled' by default):
-   * - 'disabled' or not defined -  scroll behavior is disabled;
-   * - 'center' - scroll behavior is enabled, tab is center-aligned;
-   * - 'side' - scroll behavior is enabled, tab is side-aligned;
-   * - empty or unsupported value - scroll behavior is enabled, tab is side-aligned;
-   */
-  'scrollable'?: string;
-
-  /** Defines inner element to contain {@link ESLTab} collection. Will be scrolled in a scrollable mode */
-  'scrollable-target'?: string;
-
-  /** Allowed children */
-  children: any[];
-}
diff --git a/src/modules/esl-tab/core/esl-tabs.ts b/src/modules/esl-tab/core/esl-tabs.ts
index 5f2b9886e..c4773c136 100644
--- a/src/modules/esl-tab/core/esl-tabs.ts
+++ b/src/modules/esl-tab/core/esl-tabs.ts
@@ -27,8 +27,7 @@ export class ESLTabs extends ESLBaseElement {
     return ['scrollable'];
   }
 
-  /**
-   * Scrollable mode.
+  /** Scrollable mode.
    * Supported types for different breakpoints ('disabled' by default):
    * - 'disabled' or not defined -  scroll behavior is disabled;
    * - 'center' - scroll behavior is enabled, tab is center-aligned;
diff --git a/src/modules/esl-toggleable/core.ts b/src/modules/esl-toggleable/core.ts
index efd39feb3..21676a4cb 100644
--- a/src/modules/esl-toggleable/core.ts
+++ b/src/modules/esl-toggleable/core.ts
@@ -1,5 +1,2 @@
-export type {ESLToggleableShape} from './core/esl-toggleable.shape';
-export type {ESLToggleableDispatcherShape} from './core/esl-toggleable-dispatcher.shape';
-
 export * from './core/esl-toggleable';
 export * from './core/esl-toggleable-dispatcher';
diff --git a/src/modules/esl-toggleable/core/esl-toggleable-dispatcher.shape.ts b/src/modules/esl-toggleable/core/esl-toggleable-dispatcher.shape.ts
deleted file mode 100644
index 17d0cfb52..000000000
--- a/src/modules/esl-toggleable/core/esl-toggleable-dispatcher.shape.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Tag declaration interface of {@link ESLToggleableDispatcher} element
- * Used for JSX declaration
- */
-export interface ESLToggleableDispatcherShape {
-  /** Allowed children */
-  children: [];
-}
diff --git a/src/modules/esl-toggleable/core/esl-toggleable.shape.ts b/src/modules/esl-toggleable/core/esl-toggleable.shape.ts
deleted file mode 100644
index d274ba1d8..000000000
--- a/src/modules/esl-toggleable/core/esl-toggleable.shape.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Tag declaration interface of {@link ESLToggleable} element
- * Used for JSX declaration
- */
-export interface ESLToggleableShape {
-  /** Define CSS class to add on the body element */
-  'body-class'?: string;
-  /** Define CSS class to add when the Toggleable is active */
-  'active-class'?: string;
-
-  /** Define Toggleable group meta information to organize groups */
-  'group-name'?: string;
-
-  /** Define selector to mark inner close triggers */
-  'close-trigger'?: string;
-
-  /** Enable close the Toggleable on ESC keyboard event */
-  'close-on-esc'?: boolean;
-  /** Enable close the Toggleable on a click/tap outside */
-  'close-on-outside-action'?: boolean;
-
-  /** Define selector of inner target element to place aria attributes */
-  'a11y-target'?: string;
-
-  /** Define JSON of initial params to pass to show/hide action on the start */
-  'initial-params'?: string | number;
-  /** Define JSON of default params to merge into passed action params */
-  'default-params'?: string | number;
-  /** Define JSON of hover params to pass from track hover listener */
-  'track-hover-params'?: string | number;
-
-  /** Allowed children */
-  children: any[];
-}
diff --git a/src/modules/esl-toggleable/core/esl-toggleable.ts b/src/modules/esl-toggleable/core/esl-toggleable.ts
index b5cba4eed..1c9419e84 100644
--- a/src/modules/esl-toggleable/core/esl-toggleable.ts
+++ b/src/modules/esl-toggleable/core/esl-toggleable.ts
@@ -192,7 +192,7 @@ export class ESLToggleable extends ESLBaseElement {
   /** Actual hide task to execute by toggleable task manger ({@link DelayedTask} out of the box) */
   protected hideTask(params: ToggleableActionParams) {
     if (!params.force && !this.open) return;
-    if (!params.silent && !this.$$fire('before:hide', {detail: {params}})) return;
+    if (!params.silent && !this.$$fire('before:hide',{detail: {params}})) return;
     this.open = false;
     this.onHide(params);
     if (!params.silent) this.$$fire('hide', {detail: {params}, cancelable: false});
@@ -234,7 +234,7 @@ export class ESLToggleable extends ESLBaseElement {
     return activators.get(this);
   }
   public set activator(el: HTMLElement | null | undefined) {
-    el ? activators.set(this, el) : activators.delete(this);
+    el ? activators.set(this, el): activators.delete(this);
   }
 
   /** Returns the element to apply a11y attributes */
diff --git a/src/modules/esl-trigger/core.ts b/src/modules/esl-trigger/core.ts
index 03b3f781f..9a429c924 100644
--- a/src/modules/esl-trigger/core.ts
+++ b/src/modules/esl-trigger/core.ts
@@ -1,3 +1,1 @@
-export type {ESLTriggerShape} from './core/esl-trigger.shape';
-
 export * from './core/esl-trigger';
diff --git a/src/modules/esl-trigger/core/esl-trigger.shape.ts b/src/modules/esl-trigger/core/esl-trigger.shape.ts
deleted file mode 100644
index a16ceaec5..000000000
--- a/src/modules/esl-trigger/core/esl-trigger.shape.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Tag declaration interface of {@link ESLTrigger} element
- * Used for JSX declaration
- */
-export interface ESLTriggerShape {
-  /** Define target Toggleable {@link TraversingQuery} selector. `next` by default */
-  'target'?: string;
-
-  /** Define an action to pass to the Toggleable */
-  'mode'?: 'show' | 'hide' | 'toggle';
-
-  /** Define CSS classes to set on active state */
-  'active-class'?: string;
-  /** Define target element {@link TraversingQuery} selector to set `active-class` */
-  'active-class-target'?: string;
-
-  /** Define selector for ignored inner elements */
-  'ignore'?: string;
-
-  /** Define click event tracking media query */
-  'track-click'?: boolean | string;
-  /** Define hover event tracking media query */
-  'track-hover'?: boolean | string;
-
-  /** Define selector of inner target element to place aria attributes */
-  'a11y-target'?: string;
-
-  /** Define show delay value */
-  'show-delay'?: string | number;
-  /** Define hide delay value */
-  'hide-delay'?: string | number;
-  /** Define show delay value override for hover */
-  'hover-show-delay'?: string | number;
-  /** Define hide delay value override for hover */
-  'hover-hide-delay'?: string | number;
-
-  /** Allowed children */
-  children: any[];
-}
diff --git a/src/modules/esl-trigger/core/esl-trigger.ts b/src/modules/esl-trigger/core/esl-trigger.ts
index c4fc67f3d..0b422bbf0 100644
--- a/src/modules/esl-trigger/core/esl-trigger.ts
+++ b/src/modules/esl-trigger/core/esl-trigger.ts
@@ -27,7 +27,7 @@ export class ESLTrigger extends ESLBaseElement {
   /** Target element {@link TraversingQuery} selector to set `activeClass` */
   @attr({defaultValue: ''}) public activeClassTarget: string;
 
-  /** Selector for ignored inner elements */
+  /** Selector for ignore inner elements */
   @attr({defaultValue: 'a[href]'}) public ignore: string;
 
   /** Target Toggleable {@link TraversingQuery} selector. `next` by default */
diff --git a/src/modules/esl-utils/async/throttle.ts b/src/modules/esl-utils/async/throttle.ts
index a07c68bee..03a3f643c 100644
--- a/src/modules/esl-utils/async/throttle.ts
+++ b/src/modules/esl-utils/async/throttle.ts
@@ -25,7 +25,7 @@ export function throttle<F extends AnyToAnyFnSignature>(fn: F, threshold = 250):
 
     if (!last || now >= last + threshold) {
       last = now;
-      return Promise.resolve(fn.apply(this, args));
+      fn.apply(this, args);
     }
 
     deferred = deferred || createDeferred();
@@ -37,7 +37,6 @@ export function throttle<F extends AnyToAnyFnSignature>(fn: F, threshold = 250):
       deferred!.resolve(fn.apply(this, args));
       deferred = null;
     }, threshold);
-    return deferred.promise;
   }
   Object.defineProperty(throttledSubject, 'promise', {
     get: () => deferred ? deferred.promise : Promise.resolve()
diff --git a/src/modules/esl-utils/dom/class.ts b/src/modules/esl-utils/dom/class.ts
index 882461501..faae3f5bd 100644
--- a/src/modules/esl-utils/dom/class.ts
+++ b/src/modules/esl-utils/dom/class.ts
@@ -1,5 +1,3 @@
-import {wrap} from '../misc/array';
-
 /** Describe locker elements collection per class name */
 type Locks = Map<string, Set<HTMLElement>>;
 /** Store locks for key element classes*/
@@ -68,34 +66,32 @@ export abstract class CSSClassUtils {
    * Add all classes from the class token string to the element.
    * @see CSSClassUtils
    * */
-  public static add(els: HTMLElement | HTMLElement[], cls: string | null | undefined, locker?: HTMLElement) {
-    const tokens = CSSClassUtils.splitTokens(cls);
-    wrap(els).forEach((el) => tokens.forEach((className) => add(el, className, locker)));
+  public static add(el: HTMLElement, cls: string | null | undefined, locker?: HTMLElement) {
+    CSSClassUtils.splitTokens(cls).forEach((className) => add(el, className, locker));
   }
 
   /**
    * Remove all classes from the class token string to the element.
    * @see CSSClassUtils
    * */
-  public static remove(els: HTMLElement | HTMLElement[], cls: string | null | undefined, locker?: HTMLElement) {
-    const tokens = CSSClassUtils.splitTokens(cls);
-    wrap(els).forEach((el) => tokens.forEach((className) => remove(el, className, locker)));
+  public static remove(el: HTMLElement, cls: string | null | undefined, locker?: HTMLElement) {
+    CSSClassUtils.splitTokens(cls).forEach((className) => remove(el, className, locker));
   }
 
   /**
    * Toggle all classes from the class token string on the element to the passed state.
    * @see CSSClassUtils
    * */
-  public static toggle(els: HTMLElement | HTMLElement[], cls: string | null | undefined, state: boolean, locker?: HTMLElement) {
-    (state ? CSSClassUtils.add : CSSClassUtils.remove)(els, cls, locker);
+  public static toggle(el: HTMLElement, cls: string | null | undefined, state: boolean, locker?: HTMLElement) {
+    (state ? CSSClassUtils.add : CSSClassUtils.remove)(el, cls, locker);
   }
 
   /** Remove all lockers for the element or passed element className */
-  public static unlock(els: HTMLElement | HTMLElement[], className?: string) {
+  public static unlock(el: HTMLElement, className?: string) {
     if (className) {
-      wrap(els).forEach((el) => lockStore.get(el)?.delete(className));
+      lockStore.get(el)?.delete(className);
     } else {
-      wrap(els).forEach((el) => lockStore.delete(el));
+      lockStore.delete(el);
     }
   }
 }
diff --git a/src/modules/esl-utils/dom/element.ts b/src/modules/esl-utils/dom/element.ts
index 50ddf85f8..42aa3b3d3 100644
--- a/src/modules/esl-utils/dom/element.ts
+++ b/src/modules/esl-utils/dom/element.ts
@@ -13,7 +13,7 @@ export function getDocumentElement(element: Element | Window): Element {
  * @param element - element for which to get the name
  */
 export function getNodeName(element?: Node | Window): string {
-  return element && !(element instanceof Window) ? (element.nodeName).toLowerCase() : '';
+  return element && !(element instanceof Window)? (element.nodeName).toLowerCase() : '';
 }
 
 /**
diff --git a/src/modules/esl-utils/dom/focus.ts b/src/modules/esl-utils/dom/focus.ts
index 4b2f8a482..8c4cf595c 100644
--- a/src/modules/esl-utils/dom/focus.ts
+++ b/src/modules/esl-utils/dom/focus.ts
@@ -5,7 +5,7 @@ import {TAB} from './keys';
  * Passive (should be called inside keyboard event handler)
  */
 export const handleFocusChain = (e: KeyboardEvent, first: HTMLElement, last: HTMLElement) => {
-  if (e.key !== TAB) return;
+  if (e.key !== TAB ) return;
   if (last && e.target === first && e.shiftKey) {
     last.focus();
     e.preventDefault();
diff --git a/src/modules/esl-utils/dom/rect.ts b/src/modules/esl-utils/dom/rect.ts
index 0b6d48cbd..5c92ab611 100644
--- a/src/modules/esl-utils/dom/rect.ts
+++ b/src/modules/esl-utils/dom/rect.ts
@@ -15,14 +15,14 @@ export class Rect {
    * The static method creates a new Rect instance from a rect-like object.
    * @param rect - rect-like object
    * */
-  public static from(rect: {x?: number, left?: number, y?: number, top?: number, width?: number, height?: number} = {}): Rect {
+  public static from(rect: {x?: number; left?: number; y?: number; top?: number; width?: number; height?: number} = {}): Rect {
     return new this(rect.x || rect.left, rect.y || rect.top, rect.width, rect.height);
   }
 
   public constructor(x?: number, y?: number, width?: number, height?: number) {
     this.x = x || 0;
     this.y = y || 0;
-    this.width = width || 0;
+    this.width= width || 0;
     this.height = height || 0;
   }
 
diff --git a/src/modules/esl-utils/dom/rtl.ts b/src/modules/esl-utils/dom/rtl.ts
index baf97e688..56a33e67a 100644
--- a/src/modules/esl-utils/dom/rtl.ts
+++ b/src/modules/esl-utils/dom/rtl.ts
@@ -27,7 +27,7 @@ export abstract class RTLUtils {
   }
 
   static normalizeScrollLeft(el: HTMLElement, value: number | null = null, isRtl: boolean = RTLUtils.isRtl(el)): number {
-    value = (value === null) ? el.scrollLeft : value;
+    value = (value === null) ? el.scrollLeft: value;
     switch (isRtl ? RTLUtils.scrollType : '') {
       case 'negative':
         return el.scrollWidth - el.clientWidth + value;
diff --git a/src/modules/esl-utils/misc/format.ts b/src/modules/esl-utils/misc/format.ts
index a4dcc99f8..433aab4c4 100644
--- a/src/modules/esl-utils/misc/format.ts
+++ b/src/modules/esl-utils/misc/format.ts
@@ -42,7 +42,6 @@ export function parseAspectRatio(str: string): number {
 /** Evaluate passed string or returns `defaultValue` */
 export function evaluate(str: string, defaultValue?: any): any {
   try {
-    // eslint-disable-next-line @typescript-eslint/no-implied-eval
     return str ? (new Function(`return ${str}`))() : defaultValue;
   } catch (e) {
     console.warn('Cannot parse value ', str, e);
@@ -50,13 +49,9 @@ export function evaluate(str: string, defaultValue?: any): any {
   }
 }
 
-
-/** Default RegExp to match replacements in the string for the {@link format} function */
-export const DEF_FORMAT_MATCHER = /{[{%]?([\w.]+)[%}]?}/g;
-
 /** Replace `{key}` patterns in the string from the source object */
-export function format(str: string, source: Record<string, any>, matcher: RegExp = DEF_FORMAT_MATCHER) {
-  return str.replace(matcher, (match, key) => {
+export function format(str: string, source: Record<string, any>) {
+  return str.replace(/{([\w.]+)}/g, (match, key) => {
     const val = get(source, key);
     return val === undefined ? match : val;
   });
diff --git a/src/modules/esl-utils/misc/memoize.ts b/src/modules/esl-utils/misc/memoize.ts
index d694cd799..8a7e1e1da 100644
--- a/src/modules/esl-utils/misc/memoize.ts
+++ b/src/modules/esl-utils/misc/memoize.ts
@@ -3,9 +3,9 @@ import type {AnyToAnyFnSignature} from './functions';
 /** Memoized function type */
 export type MemoizedFn<T extends AnyToAnyFnSignature> = T & {
   /** Cache instance */
-  cache: Map<null | string, ReturnType<T>>;
+  cache: Map<null | string, ReturnType<T>>,
   /** Clear memoization cache */
-  clear: () => void;
+  clear: () => void
 };
 
 /**
diff --git a/src/polyfills/list/dom.tokenList.toggle.ts b/src/polyfills/list/dom.tokenList.toggle.ts
index 2f058fdc2..772fc780e 100644
--- a/src/polyfills/list/dom.tokenList.toggle.ts
+++ b/src/polyfills/list/dom.tokenList.toggle.ts
@@ -8,7 +8,6 @@
   const testTokenList = window.document.createElement('div').classList;
 
   if (!DOMTokenListProto.toggle) return;
-  // eslint-disable-next-line
   if (testTokenList.toggle('a', false) === false) return;
 
   DOMTokenListProto.toggle = function toggle(val: string, force?: boolean) {


Test patch:
diff --git a/src/modules/esl-utils/async/test/throttle.test.ts b/src/modules/esl-utils/async/test/throttle.test.ts
index 6c2d43c2b..ca382c59c 100644
--- a/src/modules/esl-utils/async/test/throttle.test.ts
+++ b/src/modules/esl-utils/async/test/throttle.test.ts
@@ -9,14 +9,14 @@ describe('async/throttle', () => {
     const fn = jest.fn();
     const throttled = throttle(fn, 100);
 
-    expect(throttled()).toBeInstanceOf(Promise);
+    expect(throttled()).toBeUndefined();
     expect(fn).toBeCalledTimes(1);
-    jest.advanceTimersByTime(50)
-    expect(throttled()).toBeInstanceOf(Promise);
+    jest.advanceTimersByTime(50);
+    expect(throttled()).toBeUndefined();
     expect(fn).toBeCalledTimes(1);
     jest.advanceTimersByTime(100)
     expect(fn).toBeCalledTimes(2);
-    expect(throttled()).toBeInstanceOf(Promise);
+    expect(throttled()).toBeUndefined();
     expect(fn).toBeCalledTimes(3);
   });
 
@@ -25,18 +25,21 @@ describe('async/throttle', () => {
     const throttled = throttle(fn, 0);
 
     const context = {};
-    return throttled.call(context).then((val: any) => expect(val).toBe(context));
-  }, 50);
+    throttled.call(context);
+    const promise$ = throttled.promise;
+    jest.runAllTimers();
+    return expect(promise$).resolves.toBe(context);
+  });
 
   test('test deferred result', () => {
     const fn = jest.fn((n) => n + 1);
     const throttled = throttle(fn as (n: number) => number, 50);
 
     expect(throttled.promise).toBeInstanceOf(Promise);
-    expect(throttled(1)).toBeInstanceOf(Promise);
-    expect(throttled(2)).toBe(throttled.promise);
+    expect(throttled(1)).toBeUndefined();
+    expect(throttled(2)).toBeUndefined();
     expect(throttled.promise).toBeInstanceOf(Promise);
-    expect(throttled(4)).toBeInstanceOf(Promise);
+    expect(throttled(4)).toBeUndefined();;
 
     expect(fn).toBeCalledTimes(1);
     expect(fn).lastCalledWith(1);
diff --git a/src/modules/esl-utils/dom/test/class.test.ts b/src/modules/esl-utils/dom/test/class.test.ts
index debe6fcdf..b34bc7ad8 100644
--- a/src/modules/esl-utils/dom/test/class.test.ts
+++ b/src/modules/esl-utils/dom/test/class.test.ts
@@ -122,41 +122,3 @@ describe('CSSClassUtils tests:', () => {
     });
   });
 });
-
-describe('multiple targets', () => {
-  const els = [
-    document.createElement('div'),
-    document.createElement('div'),
-    document.createElement('div')
-  ];
-
-  beforeEach(() => els.forEach((el) => el.className = ''));
-  test('add', () => {
-    CSSClassUtils.add(els, 'a b');
-    for (const el of els) {
-      expect(el.classList.contains('a')).toBeTruthy();
-      expect(el.classList.contains('b')).toBeTruthy();
-    }
-    CSSClassUtils.add(els, '!a !b');
-    for (const el of els) {
-      expect(el.classList.contains('a')).toBeFalsy();
-      expect(el.classList.contains('b')).toBeFalsy();
-    }
-  });
-  test('remove', () => {
-    CSSClassUtils.remove(els, '!a !b');
-    for (const el of els) {
-      expect(el.classList.contains('a')).toBeTruthy();
-      expect(el.classList.contains('b')).toBeTruthy();
-    }
-    CSSClassUtils.remove(els, 'a b');
-    for (const el of els) {
-      expect(el.classList.contains('a')).toBeFalsy();
-      expect(el.classList.contains('b')).toBeFalsy();
-    }
-  });
-  test('trivial',  () => {
-    expect(() => CSSClassUtils.add([], 'a')).not.toThrowError();
-    expect(() => CSSClassUtils.remove([], 'a')).not.toThrowError();
-  });
-});
\ No newline at end of file
diff --git a/src/modules/esl-utils/misc/test/format.test.ts b/src/modules/esl-utils/misc/test/format.test.ts
index dd72048a8..b53339a9c 100644
--- a/src/modules/esl-utils/misc/test/format.test.ts
+++ b/src/modules/esl-utils/misc/test/format.test.ts
@@ -1,4 +1,4 @@
-import { toCamelCase, toKebabCase, unwrapParenthesis, parseAspectRatio, evaluate, format, parseNumber } from '../format';
+import {toCamelCase, toKebabCase, unwrapParenthesis, parseAspectRatio, evaluate, format, parseNumber} from '../format';
 
 describe('misc/format helper tests', () => {
   test('toKebabCase', () => {
@@ -44,7 +44,7 @@ describe('misc/format helper tests', () => {
   });
   test('evaluate', () => {
     let throwError = false;
-    jest.spyOn(console, 'warn').mockImplementation(() => { throwError = true; });
+    jest.spyOn(console, 'warn').mockImplementation(() => {throwError = true;});
     expect(evaluate('0')).toBe(0);
     expect(evaluate('true')).toBe(true);
     expect(evaluate('false')).toBe(false);
@@ -52,8 +52,8 @@ describe('misc/format helper tests', () => {
     expect(evaluate('"0"')).toBe('0');
     expect(evaluate('[1, 2]')).toEqual([1, 2]);
     expect(evaluate('{}')).toEqual({});
-    expect(evaluate('{a: 1}')).toEqual({ a: 1 });
-    expect(evaluate('{"a": "1"}')).toEqual({ a: '1' });
+    expect(evaluate('{a: 1}')).toEqual({a: 1});
+    expect(evaluate('{"a": "1"}')).toEqual({a: '1'});
     expect(throwError).toBe(false);
     expect(evaluate('{')).toBe(undefined);
     expect(throwError).toBe(true);
@@ -63,12 +63,11 @@ describe('misc/format helper tests', () => {
   describe('format', () => {
     test.each([
       ['abc', {}, 'abc'],
-      ['abc{val}', { val: 'd' }, 'abcd'],
-      ['{a.b.c}', { a: { b: { c: 'hi' } } }, 'hi'],
+      ['abc{val}', {val: 'd'}, 'abcd'],
+      ['{a.b.c}', {a: {b: {c: 'hi'}}}, 'hi'],
       ['{a}', {}, '{a}'],
-      ['{a} - {b} - {c}', { a: 1, b: 2, c: 3 }, '1 - 2 - 3'],
-      ['{a.b}{b.c}', { a: { b: 'h' }, b: { c: 'i' } }, 'hi'],
-      ['abc{%foo%}-{{bar}}', { foo: 1, bar: 5 }, 'abc1-5'],
+      ['{a} - {b} - {c}', {a: 1, b: 2, c: 3}, '1 - 2 - 3'],
+      ['{a.b}{b.c}', {a: {b: 'h'}, b: {c: 'i'}}, 'hi'],
     ])('\'%s\' using %p to \'%s\'', (tmp: string, source: any, res: string) => {
       expect(format(tmp, source)).toBe(res);
     });