]> source.dussan.org Git - sonarqube.git/commitdiff
[NO JIRA] Bootstrap custom ESLint rules
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Fri, 17 Feb 2023 13:44:09 +0000 (14:44 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 23 Mar 2023 20:02:57 +0000 (20:02 +0000)
16 files changed:
server/sonar-web/.eslintrc
server/sonar-web/design-system/.eslintrc
server/sonar-web/design-system/build.gradle
server/sonar-web/design-system/eslint-local-rules/index.js [new file with mode: 0644]
server/sonar-web/design-system/package.json
server/sonar-web/eslint-local-rules/__tests__/convert-class-to-function-component-test.js [new file with mode: 0644]
server/sonar-web/eslint-local-rules/__tests__/no-conditional-rendering-of-deferredspinner-test.js [new file with mode: 0644]
server/sonar-web/eslint-local-rules/__tests__/use-enum-test.js [new file with mode: 0644]
server/sonar-web/eslint-local-rules/__tests__/use-jest-mocked-test.js [new file with mode: 0644]
server/sonar-web/eslint-local-rules/convert-class-to-function-component.js [new file with mode: 0644]
server/sonar-web/eslint-local-rules/index.js [new file with mode: 0644]
server/sonar-web/eslint-local-rules/no-conditional-rendering-of-deferredspinner.js [new file with mode: 0644]
server/sonar-web/eslint-local-rules/use-enum.js [new file with mode: 0644]
server/sonar-web/eslint-local-rules/use-jest-mocked.js [new file with mode: 0644]
server/sonar-web/package.json
server/sonar-web/yarn.lock

index 1e45ca41a4f4c20671e2311df04504ec66e74f9f..0c445a4a9507f4993317f159ccfa7cec188917af 100644 (file)
@@ -1,9 +1,19 @@
 {
   "extends": ["sonarqube", "./.eslintrc-typescript"],
+  "plugins": ["eslint-plugin-local-rules"],
+  "ignorePatterns": ["eslint-local-rules/**/*"],
   "rules": {
     "camelcase": "off",
     "promise/no-return-wrap": "warn",
     "react/jsx-curly-brace-presence": "warn",
-    "testing-library/render-result-naming-convention": "off"
+    "testing-library/render-result-naming-convention": "off",
+    /* Local rules, defined in ./eslint-local-rules/ */
+    "local-rules/use-componentqualifier-enum": "warn",
+    "local-rules/use-metrickey-enum": "warn",
+    "local-rules/use-metrictype-enum": "warn",
+    "local-rules/use-visibility-enum": "warn",
+    "local-rules/convert-class-to-function-component": "warn",
+    "local-rules/no-conditional-rendering-of-deferredspinner": "warn",
+    "local-rules/use-jest-mocked": "warn"
   }
 }
index 181af256e976d7d39caa18db2ac7d96a29b244a0..a7266dd7eb6a6d1d94567d600a4e99e6eed10adc 100644 (file)
@@ -1,6 +1,6 @@
 {
   "extends": ["sonarqube", "../.eslintrc-typescript"],
-  "plugins": ["header", "typescript-sort-keys"],
+  "plugins": ["header", "typescript-sort-keys", "eslint-plugin-local-rules"],
   "rules": {
     // Custom SonarCloud config that differs from eslint-config-sonarqube
     "camelcase": "off",
     "no-implicit-coercion": [2, { "boolean": true, "number": true, "string": true }],
     "jest/no-large-snapshots": ["warn", { "maxSize": 200 }],
 
+    // Local rules
+    "local-rules/use-componentqualifier-enum": "warn",
+    "local-rules/use-metrickey-enum": "warn",
+    "local-rules/use-metrictype-enum": "warn",
+    "local-rules/use-visibility-enum": "warn",
+    "local-rules/convert-class-to-function-component": "warn",
+    "local-rules/no-conditional-rendering-of-deferredspinner": "warn",
+    "local-rules/use-jest-mocked": "warn",
+
     // New rules added after updating eslint packages to more recent versions than eslint-config-sonarqube
     "jest/prefer-mock-promise-shorthand": "error",
     "header/header": [
index 05e41b92dfab1c4933d3df00150dc22f358474cc..5af4116261b4357d83a605e9ac077f466dd3a37a 100644 (file)
@@ -5,6 +5,7 @@ sonar {
     property "sonar.exclusions", "src/**/__tests__/**,src/types/**,src/@types/**,src/helpers/testUtils.tsx"
     property "sonar.tests", "src"
     property "sonar.test.inclusions", "src/**/__tests__/**"
+    property "sonar.eslint.reportPaths", "eslint-report/eslint-report.json"
     property "sonar.javascript.lcov.reportPaths", "./coverage/lcov.info"
   }
 }
diff --git a/server/sonar-web/design-system/eslint-local-rules/index.js b/server/sonar-web/design-system/eslint-local-rules/index.js
new file mode 100644 (file)
index 0000000..b64b153
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+module.exports = require('../eslint-local-rules');
index bbdc8c8535dd37adaa969b3e22e3e10d9c3720fc..d49f84e5e95782634be8795e9536eed24cd6ba55 100644 (file)
@@ -29,6 +29,7 @@
     "autoprefixer": "10.4.13",
     "eslint": "8.32.0",
     "eslint-plugin-header": "3.1.1",
+    "eslint-plugin-local-rules": "1.3.2",
     "eslint-plugin-typescript-sort-keys": "2.1.0",
     "history": "5.3.0",
     "jest": "29.3.1",
diff --git a/server/sonar-web/eslint-local-rules/__tests__/convert-class-to-function-component-test.js b/server/sonar-web/eslint-local-rules/__tests__/convert-class-to-function-component-test.js
new file mode 100644 (file)
index 0000000..19f4e2a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+const { RuleTester } = require('eslint');
+const convertClassToFunctionComponent = require('../convert-class-to-function-component');
+
+const ruleTester = new RuleTester({
+  parser: require.resolve('@typescript-eslint/parser'),
+  parserOptions: {
+    ecmaVersion: 2021,
+    sourceType: 'module',
+  },
+});
+
+ruleTester.run('convert-class-to-function-component', convertClassToFunctionComponent, {
+  valid: [
+    {
+      code: `class ConditionsTable extends React.PureComponent {
+  componentDidMount() {}
+  render() {}
+}`,
+    },
+    {
+      code: `class ConditionsTable extends React.PureComponent {
+  handleClick = () => {}
+  render() {}
+}`,
+    },
+  ],
+  invalid: [
+    {
+      code: `class ConditionsTable extends React.PureComponent {
+  render() {}
+}`,
+      errors: [{ messageId: 'convertClassToFunctionComponent' }],
+    },
+    {
+      code: `class ConditionsTable extends React.PureComponent {
+  ref = null;
+  render() {}
+}`,
+      errors: [{ messageId: 'convertClassToFunctionComponent' }],
+    },
+  ],
+});
diff --git a/server/sonar-web/eslint-local-rules/__tests__/no-conditional-rendering-of-deferredspinner-test.js b/server/sonar-web/eslint-local-rules/__tests__/no-conditional-rendering-of-deferredspinner-test.js
new file mode 100644 (file)
index 0000000..960938a
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+const { RuleTester } = require('eslint');
+const noConditionalRenderingOfDeferredSpinner = require('../no-conditional-rendering-of-deferredspinner');
+
+const ruleTester = new RuleTester({
+  parser: require.resolve('@typescript-eslint/parser'),
+  parserOptions: {
+    ecmaFeatures: {
+      jsx: true,
+    },
+  },
+});
+
+ruleTester.run(
+  'no-conditional-rendering-of-deferredspinner',
+  noConditionalRenderingOfDeferredSpinner,
+  {
+    valid: [
+      {
+        code: `function MyCompontent({ loading }) {
+  return <>
+    <DeferredSpinner loading={loading} />
+  </>
+}`,
+      },
+    ],
+    invalid: [
+      {
+        code: `function MyCompontent({ loading }) {
+  return <>
+    {loading && <DeferredSpinner />}
+  </>
+}`,
+        errors: [{ messageId: 'noConditionalRenderingOfDeferredSpinner' }],
+      },
+    ],
+  }
+);
diff --git a/server/sonar-web/eslint-local-rules/__tests__/use-enum-test.js b/server/sonar-web/eslint-local-rules/__tests__/use-enum-test.js
new file mode 100644 (file)
index 0000000..1534609
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+const { RuleTester } = require('eslint');
+const useComponentQualifierEnum = require('../use-enum')(
+  ['APP', 'DIR', 'DEV', 'FIL', 'VW', 'TRK', 'SVW', 'UTS'],
+  'ComponentQualifier'
+);
+
+const ruleTester = new RuleTester({
+  parser: require.resolve('@typescript-eslint/parser'),
+});
+
+ruleTester.run('use-componentqualifier-enum', useComponentQualifierEnum, {
+  valid: [
+    {
+      code: '{ qualifier: ComponentQualifier.Project };',
+    },
+    {
+      code: 'varName === ComponentQualifier.File',
+    },
+    {
+      code: `enum ComponentQualifier {
+  Portfolio = 'VW',
+  Project = 'TRK',
+  SubPortfolio = 'SVW',
+}`,
+    },
+  ],
+  invalid: [
+    {
+      code: '{ qualifier: "TRK" };',
+      errors: [{ messageId: 'useComponentQualifierEnum' }],
+    },
+    {
+      code: 'varName === "FIL"',
+      errors: [{ messageId: 'useComponentQualifierEnum' }],
+    },
+  ],
+});
diff --git a/server/sonar-web/eslint-local-rules/__tests__/use-jest-mocked-test.js b/server/sonar-web/eslint-local-rules/__tests__/use-jest-mocked-test.js
new file mode 100644 (file)
index 0000000..89db05d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+const { RuleTester } = require('eslint');
+const useJestMocked = require('../use-jest-mocked');
+
+const ruleTester = new RuleTester({
+  parser: require.resolve('@typescript-eslint/parser'),
+});
+
+ruleTester.run('use-jest-mocked', useJestMocked, {
+  valid: [
+    {
+      code: 'jest.mocked(doSomething)',
+    },
+  ],
+  invalid: [
+    {
+      code: '(doSomething as jest.Mock).mockImplementation()',
+      errors: [{ messageId: 'useJestMocked' }],
+    },
+  ],
+});
diff --git a/server/sonar-web/eslint-local-rules/convert-class-to-function-component.js b/server/sonar-web/eslint-local-rules/convert-class-to-function-component.js
new file mode 100644 (file)
index 0000000..4075ec9
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+module.exports = {
+  meta: {
+    messages: {
+      convertClassToFunctionComponent:
+        'A class component only containing a render() method should be converted to a function component',
+    },
+  },
+  create(context) {
+    return {
+      ClassDeclaration(node) {
+        const methods = node.body.body.filter(
+          (n) =>
+            n.type === 'MethodDefinition' ||
+            (n.type === 'PropertyDefinition' &&
+              n.value &&
+              n.value.type === 'ArrowFunctionExpression')
+        );
+        if (methods.length === 1 && methods[0].key.name === 'render') {
+          context.report({ node, messageId: 'convertClassToFunctionComponent' });
+        }
+      },
+    };
+  },
+};
diff --git a/server/sonar-web/eslint-local-rules/index.js b/server/sonar-web/eslint-local-rules/index.js
new file mode 100644 (file)
index 0000000..3bd8c82
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+module.exports = {
+  'use-jest-mocked': require('./use-jest-mocked'),
+  'convert-class-to-function-component': require('./convert-class-to-function-component'),
+  'no-conditional-rendering-of-deferredspinner': require('./no-conditional-rendering-of-deferredspinner'),
+  'use-visibility-enum': require('./use-enum')(['public', 'private'], 'Visibility'),
+  'use-componentqualifier-enum': require('./use-enum')(
+    ['APP', 'DIR', 'DEV', 'FIL', 'VW', 'TRK', 'SVW', 'UTS'],
+    'ComponentQualifier',
+    'representing qualifiers'
+  ),
+  'use-metrickey-enum': require('./use-enum')(
+    [
+      'alert_status',
+      'blocker_violations',
+      'branch_coverage',
+      'bugs',
+      'burned_budget',
+      'business_value',
+      'class_complexity',
+      'classes',
+      'code_smells',
+      'cognitive_complexity',
+      'comment_lines',
+      'comment_lines_data',
+      'comment_lines_density',
+      'complexity',
+      'complexity_in_classes',
+      'complexity_in_functions',
+      'conditions_to_cover',
+      'confirmed_issues',
+      'coverage',
+      'critical_violations',
+      'development_cost',
+      'directories',
+      'duplicated_blocks',
+      'duplicated_files',
+      'duplicated_lines',
+      'duplicated_lines_density',
+      'duplications_data',
+      'effort_to_reach_maintainability_rating_a',
+      'executable_lines_data',
+      'false_positive_issues',
+      'file_complexity',
+      'file_complexity_distribution',
+      'filename_size',
+      'filename_size_rating',
+      'files',
+      'function_complexity',
+      'function_complexity_distribution',
+      'functions',
+      'generated_lines',
+      'generated_ncloc',
+      'info_violations',
+      'last_change_on_maintainability_rating',
+      'last_change_on_releasability_rating',
+      'last_change_on_reliability_rating',
+      'last_change_on_security_rating',
+      'last_change_on_security_review_rating',
+      'last_commit_date',
+      'leak_projects',
+      'line_coverage',
+      'lines',
+      'lines_to_cover',
+      'maintainability_rating_effort',
+      'major_violations',
+      'minor_violations',
+      'ncloc',
+      'ncloc_data',
+      'ncloc_language_distribution',
+      'new_blocker_violations',
+      'new_branch_coverage',
+      'new_bugs',
+      'new_code_smells',
+      'new_conditions_to_cover',
+      'new_coverage',
+      'new_critical_violations',
+      'new_development_cost',
+      'new_duplicated_blocks',
+      'new_duplicated_lines',
+      'new_duplicated_lines_density',
+      'new_info_violations',
+      'new_line_coverage',
+      'new_lines',
+      'new_lines_to_cover',
+      'new_maintainability_rating',
+      'new_major_violations',
+      'new_minor_violations',
+      'new_reliability_rating',
+      'new_reliability_remediation_effort',
+      'new_security_hotspots',
+      'new_security_hotspots_reviewed',
+      'new_security_rating',
+      'new_security_remediation_effort',
+      'new_security_review_rating',
+      'new_sqale_debt_ratio',
+      'new_technical_debt',
+      'new_uncovered_conditions',
+      'new_uncovered_lines',
+      'new_violations',
+      'new_vulnerabilities',
+      'open_issues',
+      'projects',
+      'public_api',
+      'public_documented_api_density',
+      'public_undocumented_api',
+      'quality_gate_details',
+      'quality_profiles',
+      'releasability_effort',
+      'releasability_rating',
+      'reliability_rating',
+      'reliability_rating_effort',
+      'reliability_remediation_effort',
+      'reopened_issues',
+      'security_hotspots',
+      'security_hotspots_reviewed',
+      'security_rating',
+      'security_rating_effort',
+      'security_remediation_effort',
+      'security_review_rating',
+      'security_review_rating_effort',
+      'skipped_tests',
+      'sonarjava_feedback',
+      'sqale_debt_ratio',
+      'sqale_index',
+      'sqale_rating',
+      'statements',
+      'team_at_sonarsource',
+      'team_size',
+      'test_errors',
+      'test_execution_time',
+      'test_failures',
+      'test_success_density',
+      'tests',
+      'uncovered_conditions',
+      'uncovered_lines',
+      'violations',
+      'vulnerabilities',
+      'wont_fix_issues',
+    ],
+    'MetricKey',
+    'representing metric keys'
+  ),
+  'use-metrictype-enum': require('./use-enum')(
+    ['RATING', 'PERCENT', 'INT', 'LEVEL', 'SHORT_INT', 'SHORT_WORK_DUR', 'DATA'],
+    'MetricType',
+    'representing metric types'
+  ),
+};
diff --git a/server/sonar-web/eslint-local-rules/no-conditional-rendering-of-deferredspinner.js b/server/sonar-web/eslint-local-rules/no-conditional-rendering-of-deferredspinner.js
new file mode 100644 (file)
index 0000000..3db1292
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+module.exports = {
+  meta: {
+    messages: {
+      noConditionalRenderingOfDeferredSpinner:
+        'For accessibility reasons, you should not conditionally render a <DeferredSpinner />. Always render it, and pass a loading prop instead.',
+    },
+  },
+  create(context) {
+    return {
+      JSXExpressionContainer(node) {
+        if (
+          node.expression.type === 'LogicalExpression' &&
+          node.expression.right.type === 'JSXElement' &&
+          node.expression.right.openingElement.name.name === 'DeferredSpinner'
+        ) {
+          context.report({ node, messageId: 'noConditionalRenderingOfDeferredSpinner' });
+        }
+      },
+    };
+  },
+};
diff --git a/server/sonar-web/eslint-local-rules/use-enum.js b/server/sonar-web/eslint-local-rules/use-enum.js
new file mode 100644 (file)
index 0000000..50a840b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+module.exports = (values, name, help) => ({
+  meta: {
+    messages: {
+      [`use${name}Enum`]: `Hard-coded strings ${
+        help ? help + ' ' : ''
+      }are not allowed; use the ${name} enum instead`,
+    },
+  },
+  create(context) {
+    return {
+      Literal(node) {
+        if (node.parent.type !== 'TSEnumMember' && values.includes(node.value)) {
+          context.report({ node, messageId: `use${name}Enum` });
+        }
+      },
+    };
+  },
+});
diff --git a/server/sonar-web/eslint-local-rules/use-jest-mocked.js b/server/sonar-web/eslint-local-rules/use-jest-mocked.js
new file mode 100644 (file)
index 0000000..c70cd41
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+module.exports = {
+  meta: {
+    messages: {
+      useJestMocked: 'Prefer using jest.mocked(func) instead of (func as jest.Mock)',
+    },
+  },
+  create(context) {
+    return {
+      TSAsExpression(node) {
+        if (node.typeAnnotation.typeName) {
+          const { left, right } = node.typeAnnotation.typeName;
+          if (left && left.name === 'jest' && right && right.name === 'Mock') {
+            context.report({ node, messageId: 'useJestMocked' });
+          }
+        }
+      },
+    };
+  },
+};
index ee69f7c958d9e5fd964e97a55583fced59e00bdb..28011ea62caee7a10422d5476f6e4b0f68cd1392 100644 (file)
@@ -83,6 +83,7 @@
     "eslint-plugin-jest": "27.2.1",
     "eslint-plugin-jest-dom": "4.0.3",
     "eslint-plugin-jsx-a11y": "6.7.1",
+    "eslint-plugin-local-rules": "1.3.2",
     "eslint-plugin-promise": "6.1.1",
     "eslint-plugin-react": "7.32.1",
     "eslint-plugin-react-hooks": "4.6.0",
     "build": "node scripts/build.js",
     "build-release": "yarn install --immutable && node scripts/build.js release",
     "test": "jest",
+    "test-eslint-local-rules": "jest eslint-local-rules",
     "format": "prettier --write --list-different \"src/main/js/**/*.{js,ts,tsx,css}\"",
     "format-check": "prettier --list-different \"src/main/js/**/*.{js,ts,tsx,css}\"",
     "lint": "eslint --ext js,ts,tsx --quiet src/main/js",
index 5a1d45ae8fe6b1a785e4a2c7485bc0b6c331c92d..08ed270d3b9fa61cd641036678044cfe51078395 100644 (file)
@@ -4503,6 +4503,7 @@ __metadata:
     eslint-plugin-jest: 27.2.1
     eslint-plugin-jest-dom: 4.0.3
     eslint-plugin-jsx-a11y: 6.7.1
+    eslint-plugin-local-rules: 1.3.2
     eslint-plugin-promise: 6.1.1
     eslint-plugin-react: 7.32.1
     eslint-plugin-react-hooks: 4.6.0
@@ -6206,6 +6207,7 @@ __metadata:
     autoprefixer: 10.4.13
     eslint: 8.32.0
     eslint-plugin-header: 3.1.1
+    eslint-plugin-local-rules: 1.3.2
     eslint-plugin-typescript-sort-keys: 2.1.0
     history: 5.3.0
     jest: 29.3.1
@@ -7099,6 +7101,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"eslint-plugin-local-rules@npm:1.3.2":
+  version: 1.3.2
+  resolution: "eslint-plugin-local-rules@npm:1.3.2"
+  checksum: d1d94c0832d7a5e1686c4d685614c407998e7a60318893a405fb8c97c3856b05a8d9479c20ad2799667a59ebfebc4c4f3268528d21d849d2062dee2041b9e909
+  languageName: node
+  linkType: hard
+
 "eslint-plugin-promise@npm:6.1.1":
   version: 6.1.1
   resolution: "eslint-plugin-promise@npm:6.1.1"