From de5cc79302f441ac4e079031be163f599f2aa3e5 Mon Sep 17 00:00:00 2001 From: Elise DUBILLOT Date: Thu, 10 Aug 2023 13:43:57 +0200 Subject: [PATCH 1/4] add rule no-empty-image-src-attribute --- CHANGELOG.md | 1 + eslint-plugin/README.md | 1 + .../rules/no-empty-image-src-attribute.md | 26 +++++++ .../lib/rules/no-empty-image-src-attribute.js | 58 +++++++++++++++ eslint-plugin/tests/lib/files/logo.svg | 0 .../lib/rules/no-empty-image-src-attribute.js | 73 +++++++++++++++++++ 6 files changed, 159 insertions(+) create mode 100644 eslint-plugin/docs/rules/no-empty-image-src-attribute.md create mode 100644 eslint-plugin/lib/rules/no-empty-image-src-attribute.js create mode 100644 eslint-plugin/tests/lib/files/logo.svg create mode 100644 eslint-plugin/tests/lib/rules/no-empty-image-src-attribute.js diff --git a/CHANGELOG.md b/CHANGELOG.md index ccd92e5..1c4df01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- [#19](https://github.com/green-code-initiative/ecoCode-javascript/pull/19) add rule `@ecocode/no-empty-image-src-attribute` - [#14](https://github.com/green-code-initiative/ecoCode-javascript/pull/14) Create SonarQube plugin - [#12](https://github.com/green-code-initiative/ecoCode-javascript/issues/12) Pack ESLint plugin into SonarQube plugin - [#16](https://github.com/green-code-initiative/ecoCode-javascript/pull/16) Use centralized rules specifications diff --git a/eslint-plugin/README.md b/eslint-plugin/README.md index c6188f2..768adb9 100644 --- a/eslint-plugin/README.md +++ b/eslint-plugin/README.md @@ -59,6 +59,7 @@ Add `@ecocode` to the `plugins` section of your `.eslintrc`, followed by rules c | Name | Description | ⚠️ | | :------------------------------------------------------------------------------------- | :--------------------------------------------------------- | :- | | [avoid-high-accuracy-geolocation](docs/rules/avoid-high-accuracy-geolocation.md) | Avoid using high accuracy geolocation in web applications. | ✅ | +| [no-empty-image-src-attribute](docs/rules/no-empty-image-src-attribute.md) | Disallow usage of image with empty source attribute | ✅ | | [no-import-all-from-library](docs/rules/no-import-all-from-library.md) | Should not import all from library | ✅ | | [no-multiple-access-dom-element](docs/rules/no-multiple-access-dom-element.md) | Disallow multiple access of same DOM element. | ✅ | | [no-multiple-style-changes](docs/rules/no-multiple-style-changes.md) | Disallow multiple style changes at once. | ✅ | diff --git a/eslint-plugin/docs/rules/no-empty-image-src-attribute.md b/eslint-plugin/docs/rules/no-empty-image-src-attribute.md new file mode 100644 index 0000000..a160a5a --- /dev/null +++ b/eslint-plugin/docs/rules/no-empty-image-src-attribute.md @@ -0,0 +1,26 @@ +# Disallow usage of image with empty source attribute (`@ecocode/no-empty-image-src-attribute`) + +⚠️ This rule _warns_ in the ✅ `recommended` config. + + + +## Rule Details + +This rule aims to prohibit the usage of without specifying its source attribute because it causes extra and unnecessary http requests. This rule is build for the [react library](https://react.dev/) and JSX. + +## Examples + +Examples of **non compliant** code for this rule: + +```js + + +``` + +Examples of **compliant** code for this rule: + +```js +import imgSvg from './img.svg' + + +``` diff --git a/eslint-plugin/lib/rules/no-empty-image-src-attribute.js b/eslint-plugin/lib/rules/no-empty-image-src-attribute.js new file mode 100644 index 0000000..c966fd9 --- /dev/null +++ b/eslint-plugin/lib/rules/no-empty-image-src-attribute.js @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2023 Green Code Initiative + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +"use strict"; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: "suggestion", + docs: { + description: "Disallow usage of image with empty source attribute", + category: "eco-design", + recommended: "warn", + }, + messages: { + SpecifySrcAttribute: + "Make sure to specify src attribute when using .", + }, + schema: [], + }, + create(context) { + return { + JSXOpeningElement(node) { + if (node.name.name === "img") { + const srcValue = node.attributes.find( + (attr) => attr.name.name === "src", + ); + if (srcValue && srcValue.value && srcValue.value.value === "") { + //to prevent Empty image + context.report({ + node: srcValue, + messageId: "SpecifySrcAttribute", + }); + } else if (!srcValue) { + //to prevent + context.report({ + node, + messageId: "SpecifySrcAttribute", + }); + } + } + }, + }; + }, +}; diff --git a/eslint-plugin/tests/lib/files/logo.svg b/eslint-plugin/tests/lib/files/logo.svg new file mode 100644 index 0000000..e69de29 diff --git a/eslint-plugin/tests/lib/rules/no-empty-image-src-attribute.js b/eslint-plugin/tests/lib/rules/no-empty-image-src-attribute.js new file mode 100644 index 0000000..4092c49 --- /dev/null +++ b/eslint-plugin/tests/lib/rules/no-empty-image-src-attribute.js @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2023 Green Code Initiative + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require("../../../lib/rules/no-empty-image-src-attribute"); +const RuleTester = require("eslint").RuleTester; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + parserOptions: { + ecmaVersion: 2021, + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, + }, +}); +const expectedError1 = { + messageId: "SpecifySrcAttribute", + type: "JSXAttribute", +}; +const expectedError2 = { + messageId: "SpecifySrcAttribute", + type: "JSXOpeningElement", +}; + +ruleTester.run("image-src-attribute-not-empty", rule, { + valid: [ + ` + This is a SVG image + `, + ` + import logoSvg from "../files/logo.svg"; + This is a SVG image + `, + ], + + invalid: [ + { + code: ` + + `, + errors: [expectedError1], + }, + { + code: ` + This is an empty image + `, + errors: [expectedError2], + }, + ], +}); From 9ab6fe23a33c0fb1de084d3606ca878c22d49898 Mon Sep 17 00:00:00 2001 From: utarwyn Date: Fri, 4 Aug 2023 20:07:28 +0200 Subject: [PATCH 2/4] Add provenance when publishing package --- .github/workflows/publish.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9658d49..5a2b6ae 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,6 +14,8 @@ env: jobs: publish-npm: runs-on: ubuntu-latest + permissions: + id-token: write steps: - name: Checkout tag "${{ github.ref_name }}" uses: actions/checkout@v3 @@ -34,7 +36,7 @@ jobs: run: cp LICENSE.md eslint-plugin/ - name: Publish package on NPM - run: npm publish --access public + run: npm publish --provenance --access public working-directory: eslint-plugin env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} From 5bacac75dac024afd617e0d5c15220aabb39cd5d Mon Sep 17 00:00:00 2001 From: utarwyn Date: Tue, 8 Aug 2023 19:35:10 +0200 Subject: [PATCH 3/4] Simplify list of files to pack with npm --- eslint-plugin/.npmignore | 5 ----- eslint-plugin/package.json | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) delete mode 100644 eslint-plugin/.npmignore diff --git a/eslint-plugin/.npmignore b/eslint-plugin/.npmignore deleted file mode 100644 index 70ba64f..0000000 --- a/eslint-plugin/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -* -!lib/**/* -!package.json -!LICENSE.md -!README.md diff --git a/eslint-plugin/package.json b/eslint-plugin/package.json index 82cb2d0..d0a2e2b 100644 --- a/eslint-plugin/package.json +++ b/eslint-plugin/package.json @@ -17,6 +17,9 @@ "license": "GPL-3.0", "author": "Green Code Initiative", "main": "./lib/standalone.js", + "files": [ + "lib" + ], "scripts": { "clean": "rimraf dist", "lint": "npm-run-all \"lint:*\"", From a2e188a1653d0a791abb2deabcca968c1bae8f0c Mon Sep 17 00:00:00 2001 From: Elise DUBILLOT Date: Tue, 25 Jul 2023 14:11:56 +0200 Subject: [PATCH 4/4] add rule limit-db-query-results --- CHANGELOG.md | 1 + eslint-plugin/README.md | 1 + .../docs/rules/limit-db-query-results.md | 23 +++++++ .../lib/rules/limit-db-query-results.js | 55 ++++++++++++++++ .../tests/lib/rules/limit-db-query-results.js | 62 +++++++++++++++++++ 5 files changed, 142 insertions(+) create mode 100644 eslint-plugin/docs/rules/limit-db-query-results.md create mode 100644 eslint-plugin/lib/rules/limit-db-query-results.js create mode 100644 eslint-plugin/tests/lib/rules/limit-db-query-results.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c4df01..5a1b097 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - [#19](https://github.com/green-code-initiative/ecoCode-javascript/pull/19) add rule `@ecocode/no-empty-image-src-attribute` +- [#18](https://github.com/green-code-initiative/ecoCode-javascript/pull/18) add rule `@ecocode/limit-db-query-results` - [#14](https://github.com/green-code-initiative/ecoCode-javascript/pull/14) Create SonarQube plugin - [#12](https://github.com/green-code-initiative/ecoCode-javascript/issues/12) Pack ESLint plugin into SonarQube plugin - [#16](https://github.com/green-code-initiative/ecoCode-javascript/pull/16) Use centralized rules specifications diff --git a/eslint-plugin/README.md b/eslint-plugin/README.md index 768adb9..07f5451 100644 --- a/eslint-plugin/README.md +++ b/eslint-plugin/README.md @@ -59,6 +59,7 @@ Add `@ecocode` to the `plugins` section of your `.eslintrc`, followed by rules c | Name | Description | ⚠️ | | :------------------------------------------------------------------------------------- | :--------------------------------------------------------- | :- | | [avoid-high-accuracy-geolocation](docs/rules/avoid-high-accuracy-geolocation.md) | Avoid using high accuracy geolocation in web applications. | ✅ | +| [limit-db-query-results](docs/rules/limit-db-query-results.md) | Should limit the number of returns for a SQL query | ✅ | | [no-empty-image-src-attribute](docs/rules/no-empty-image-src-attribute.md) | Disallow usage of image with empty source attribute | ✅ | | [no-import-all-from-library](docs/rules/no-import-all-from-library.md) | Should not import all from library | ✅ | | [no-multiple-access-dom-element](docs/rules/no-multiple-access-dom-element.md) | Disallow multiple access of same DOM element. | ✅ | diff --git a/eslint-plugin/docs/rules/limit-db-query-results.md b/eslint-plugin/docs/rules/limit-db-query-results.md new file mode 100644 index 0000000..4626876 --- /dev/null +++ b/eslint-plugin/docs/rules/limit-db-query-results.md @@ -0,0 +1,23 @@ +# Should limit the number of returns for a SQL query (`@ecocode/limit-db-query-results`) + +⚠️ This rule _warns_ in the ✅ `recommended` config. + + + +## Rule Details + +This rule aims at reducing CPU consumption by limiting the number of returns for a single SQL query. + +## Examples + +Examples of **non compliant** code for this rule: + +```js +const query = "SELECT * FROM clients"; +``` + +Examples of **compliant** code for this rule: + +```js +const query = "SELECT columns FROM table_name FETCH FIRST number ROWS ONLY"; +``` diff --git a/eslint-plugin/lib/rules/limit-db-query-results.js b/eslint-plugin/lib/rules/limit-db-query-results.js new file mode 100644 index 0000000..9a7b2e7 --- /dev/null +++ b/eslint-plugin/lib/rules/limit-db-query-results.js @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2023 Green Code Initiative + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +"use strict"; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: "suggestion", + docs: { + description: "Should limit the number of returns for a SQL query", + category: "eco-design", + recommended: "warn", + }, + messages: { + LimitTheNumberOfReturns: + "Try and limit the number of data returned for a single query (by using the LIMIT keyword for example)", + }, + schema: [], + }, + create(context) { + //list of limiting clauses to check against + const limitingClauses = ["LIMIT", "TOP", "ROW_NUMBER", "FETCH FIRST"]; + return { + Literal: function (node) { + if (typeof node.value == "string") { + const query = node.value.toUpperCase(); + if ( + query.includes("SELECT") && + query.includes("FROM") && + !limitingClauses.some((clause) => query.includes(clause)) + ) { + context.report({ + node: node, + messageId: "LimitTheNumberOfReturns", + }); + } + } + }, + }; + }, +}; diff --git a/eslint-plugin/tests/lib/rules/limit-db-query-results.js b/eslint-plugin/tests/lib/rules/limit-db-query-results.js new file mode 100644 index 0000000..6658c42 --- /dev/null +++ b/eslint-plugin/tests/lib/rules/limit-db-query-results.js @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2023 Green Code Initiative + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +"use strict"; +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require("../../../lib/rules/limit-db-query-results"), + RuleTester = require("eslint").RuleTester; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + parserOptions: { + ecmaVersion: 6, + sourceType: "module", + }, +}); +const expectedError = { + messageId: "LimitTheNumberOfReturns", + type: "Literal", +}; + +ruleTester.run("limit-db-query-results", rule, { + valid: [ + ` + const query = "SELECT * FROM customers LIMIT 10;"; + `, + ` + const query = "SELECT TOP 5 * FROM products;"; + `, + ` + const query = "SELECT * FROM orders FETCH FIRST 20 ROWS ONLY;"; + `, + ` + const query = "WITH numbered_customers AS (SELECT *, ROW_NUMBER() OVER (ORDER BY customer_id) AS row_num FROM customers) SELECT * FROM numbered_customers WHERE row_num <= 50;"; + `, + ], + + invalid: [ + { + code: `const query = "SELECT * FROM bikes;";`, + errors: [expectedError], + }, + ], +});