diff --git a/projects/eslint-plugin-experience/configs/no-restricted-syntax.js b/projects/eslint-plugin-experience/configs/no-restricted-syntax.js index cc95d64f..fe7cc53f 100644 --- a/projects/eslint-plugin-experience/configs/no-restricted-syntax.js +++ b/projects/eslint-plugin-experience/configs/no-restricted-syntax.js @@ -44,10 +44,6 @@ module.exports = { message: "Use `map(x => x?.foo?.bar)` instead of `pluck('foo', 'bar')`", }, - { - selector: 'ForOfStatement', - message: 'Use `forEach` instead of `for-of`', - }, ], }, }, diff --git a/projects/eslint-plugin-experience/configs/taiga.js b/projects/eslint-plugin-experience/configs/taiga.js index 3e221443..99df094b 100644 --- a/projects/eslint-plugin-experience/configs/taiga.js +++ b/projects/eslint-plugin-experience/configs/taiga.js @@ -23,6 +23,7 @@ module.exports = { ], '@taiga-ui/experience/strict-tui-doc-example': 'error', '@taiga-ui/experience/no-assert-without-ng-dev-mode': 'error', + '@taiga-ui/experience/no-simple-for-of': 'error', '@taiga-ui/experience/decorator-key-sort': [ 'error', { diff --git a/projects/eslint-plugin-experience/index.js b/projects/eslint-plugin-experience/index.js index db38e215..a09bd2a9 100644 --- a/projects/eslint-plugin-experience/index.js +++ b/projects/eslint-plugin-experience/index.js @@ -34,6 +34,7 @@ module.exports = { rules: { 'injection-token-description': require('./rules/injection-token-description'), 'no-deep-imports': require('./rules/no-deep-imports'), + 'no-simple-for-of': require('./rules/no-simple-for-of'), 'prefer-inject-decorator': require('./rules/prefer-inject-decorator'), 'prefer-self-destroy-service': require('./rules/prefer-self-destroy-service'), 'no-typeof': require('./rules/no-typeof'), diff --git a/projects/eslint-plugin-experience/rules/no-simple-for-of.js b/projects/eslint-plugin-experience/rules/no-simple-for-of.js new file mode 100644 index 00000000..d51a92b7 --- /dev/null +++ b/projects/eslint-plugin-experience/rules/no-simple-for-of.js @@ -0,0 +1,47 @@ +/** + * @type {import('eslint').Rule.RuleModule} + */ +module.exports = { + meta: { + type: 'problem', + schema: [], + }, + create(context) { + return { + /** + * @type {import('eslint').Rule.Node} + * @return {*} + */ + ForOfStatement(node) { + const isSimpleForOf = !findExpressions(node, [ + 'AwaitExpression', + 'BreakStatement', + 'ContinueStatement', + ]); + + if (isSimpleForOf) { + context.report({ + node: node, + message: `Don't use simple "for-of" instead of "forEach"`, + }); + } + }, + }; + }, +}; + +function findExpressions(node, keys) { + if (keys.includes(node?.type) || keys.includes(node?.expression?.type)) { + return true; + } + + if (Array.isArray(node?.body)) { + return node?.body?.some?.(item => findExpressions(item, keys)); + } else if (!!node?.body) { + return findExpressions(node?.body, keys); + } else if (!!node?.consequent) { + return findExpressions(node?.consequent, keys); + } + + return false; +}