From 7e41dc7323cbe9dc782d3eb78a90fef651b72e19 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Tue, 6 Feb 2024 11:40:53 +0100 Subject: [PATCH 01/47] feat(packages/eslint-plugin-sui): create few rules --- packages/eslint-plugin-sui/README.md | 58 ++++++++++++ .../docs/rules/factory-pattern.md | 35 +++++++ packages/eslint-plugin-sui/package.json | 39 ++++++++ packages/eslint-plugin-sui/src/index.js | 14 +++ .../src/rules/factory-pattern.js | 65 +++++++++++++ .../src/rules/forbidden-require.js | 46 +++++++++ .../src/rules/naming-convention.js | 46 +++++++++ .../src/rules/serialize-deserialize.js | 93 +++++++++++++++++++ .../tests/src/rules/factory-pattern.js | 30 ++++++ 9 files changed, 426 insertions(+) create mode 100644 packages/eslint-plugin-sui/README.md create mode 100644 packages/eslint-plugin-sui/docs/rules/factory-pattern.md create mode 100644 packages/eslint-plugin-sui/package.json create mode 100644 packages/eslint-plugin-sui/src/index.js create mode 100644 packages/eslint-plugin-sui/src/rules/factory-pattern.js create mode 100644 packages/eslint-plugin-sui/src/rules/forbidden-require.js create mode 100644 packages/eslint-plugin-sui/src/rules/naming-convention.js create mode 100644 packages/eslint-plugin-sui/src/rules/serialize-deserialize.js create mode 100644 packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js diff --git a/packages/eslint-plugin-sui/README.md b/packages/eslint-plugin-sui/README.md new file mode 100644 index 000000000..07481eb4d --- /dev/null +++ b/packages/eslint-plugin-sui/README.md @@ -0,0 +1,58 @@ +# eslint-plugin-sui + +Set of sui lint rules + +## Installation + +You'll first need to install [ESLint](https://eslint.org/): + +```sh +npm i eslint --save-dev +``` + +Next, install `eslint-plugin-sui`: + +```sh +npm install eslint-plugin-sui --save-dev +``` + +## Usage + +Add `sui` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix: + +```json +{ + "plugins": [ + "sui" + ] +} +``` + + +Then configure the rules you want to use under the rules section. + +```json +{ + "rules": { + "sui/rule-name": 2 + } +} +``` + + + +## Configurations + + +TODO: Run eslint-doc-generator to generate the configs list (or delete this section if no configs are offered). + + + + +## Rules + + +TODO: Run eslint-doc-generator to generate the rules list. + + + diff --git a/packages/eslint-plugin-sui/docs/rules/factory-pattern.md b/packages/eslint-plugin-sui/docs/rules/factory-pattern.md new file mode 100644 index 000000000..c6699910d --- /dev/null +++ b/packages/eslint-plugin-sui/docs/rules/factory-pattern.md @@ -0,0 +1,35 @@ +# Ensure that our classes are using the convetion of has a static create method as factory. (`factory-pattern`) + +Please describe the origin of the rule here. + +## Rule Details + +This rule aims to... + +Examples of **incorrect** code for this rule: + +```js + +// fill me in + +``` + +Examples of **correct** code for this rule: + +```js + +// fill me in + +``` + +### Options + +If there are any options, describe them here. Otherwise, delete this section. + +## When Not To Use It + +Give a short description of when it would be appropriate to turn off this rule. + +## Further Reading + +If there are other links that describe the issue this rule addresses, please include them here in a bulleted list. diff --git a/packages/eslint-plugin-sui/package.json b/packages/eslint-plugin-sui/package.json new file mode 100644 index 000000000..99d36c4a1 --- /dev/null +++ b/packages/eslint-plugin-sui/package.json @@ -0,0 +1,39 @@ +{ + "name": "eslint-plugin-sui", + "version": "0.0.0", + "description": "Set of sui lint rules", + "keywords": [ + "eslint", + "eslintplugin", + "eslint-plugin" + ], + "author": "Sui", + "main": "./src/index.js", + "exports": "./src/index.js", + "scripts": { + "lint": "npm-run-all \"lint:*\"", + "lint:eslint-docs": "npm-run-all \"update:eslint-docs -- --check\"", + "lint:js": "eslint .", + "test": "mocha tests --recursive", + "update:eslint-docs": "eslint-doc-generator" + }, + "dependencies": { + "requireindex": "^1.2.0", + "string-dedent": "^3.0.1" + }, + "devDependencies": { + "eslint": "^8.19.0", + "eslint-doc-generator": "^1.0.0", + "eslint-plugin-eslint-plugin": "^5.0.0", + "eslint-plugin-node": "^11.1.0", + "mocha": "^10.0.0", + "npm-run-all": "^4.1.5" + }, + "engines": { + "node": "^14.17.0 || ^16.0.0 || >= 18.0.0" + }, + "peerDependencies": { + "eslint": ">=7" + }, + "license": "ISC" +} diff --git a/packages/eslint-plugin-sui/src/index.js b/packages/eslint-plugin-sui/src/index.js new file mode 100644 index 000000000..84d25af60 --- /dev/null +++ b/packages/eslint-plugin-sui/src/index.js @@ -0,0 +1,14 @@ +const FactoryPattern = require('./rules/factory-pattern.js') +const SerializeDeserialize = require('./rules/serialize-deserialize.js') + +// ------------------------------------------------------------------------------ +// Plugin Definition +// ------------------------------------------------------------------------------ + +// import all rules in lib/rules +module.exports = { + rules: { + 'factory-pattern': FactoryPattern, + 'serialize-deserialize': SerializeDeserialize + } +} diff --git a/packages/eslint-plugin-sui/src/rules/factory-pattern.js b/packages/eslint-plugin-sui/src/rules/factory-pattern.js new file mode 100644 index 000000000..779da9890 --- /dev/null +++ b/packages/eslint-plugin-sui/src/rules/factory-pattern.js @@ -0,0 +1,65 @@ +/** + * @fileoverview Ensure that our classes are using the convetion of has a static create method as factory. + * @author factory pattern + */ +'use strict' + +const dedent = require('string-dedent') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'ensure to define at least one factory function', + recommended: true, + url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements/02-project-structure.md' + }, + fixable: null, + schema: [], + messages: { + notFoundFactoryFunction: dedent` + You have to define at least one static function that return an instance of your class. + Avoid to use the 'new' keyword directly in your code. + Use always a factory function + ` + } + }, + create: function (context) { + // variables should be defined here + + // ---------------------------------------------------------------------- + // Helpers + // ---------------------------------------------------------------------- + + // any helper functions should go here or else delete this section + + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + + return { + ClassDeclaration(node) { + const hasStaticFactoryMethod = Boolean( + node.body?.body?.find(methodDefinition => { + return ( + methodDefinition.static && + methodDefinition.value?.body?.body?.find(body => body.type === 'ReturnStatement')?.argument?.callee.name === node.id.name // eslint-disable-line + ) + }) + ) + + if (!hasStaticFactoryMethod) { + return context.report({ + node, + messageId: 'notFoundFactoryFunction' + }) + } + } + } + } +} diff --git a/packages/eslint-plugin-sui/src/rules/forbidden-require.js b/packages/eslint-plugin-sui/src/rules/forbidden-require.js new file mode 100644 index 000000000..ec3dbe74e --- /dev/null +++ b/packages/eslint-plugin-sui/src/rules/forbidden-require.js @@ -0,0 +1,46 @@ +/** + * @fileoverview Ensure that our coda doesnt have require (CJS) styles + * @author factory pattern + */ +'use strict' + +const dedent = require('string-dedent') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'ensure to use only ESM (import) style', + recommended: true, + url: null + }, + fixable: null, + schema: [], + messages: { + badFileName: dedent``, + badClassName: dedent`` + } + }, + create: function (context) { + // variables should be defined here + + // ---------------------------------------------------------------------- + // Helpers + // ---------------------------------------------------------------------- + + // any helper functions should go here or else delete this section + + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + + return { + ClassDeclaration(node) {} + } + } +} diff --git a/packages/eslint-plugin-sui/src/rules/naming-convention.js b/packages/eslint-plugin-sui/src/rules/naming-convention.js new file mode 100644 index 000000000..68477031f --- /dev/null +++ b/packages/eslint-plugin-sui/src/rules/naming-convention.js @@ -0,0 +1,46 @@ +/** + * @fileoverview Ensure that our classes are using the naming convention for UseCases, Services and Repositories + * @author factory pattern + */ +'use strict' + +const dedent = require('string-dedent') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'ensure to use a proper naming convention', + recommended: true, + url: null + }, + fixable: null, + schema: [], + messages: { + badFileName: dedent``, + badClassName: dedent`` + } + }, + create: function (context) { + // variables should be defined here + + // ---------------------------------------------------------------------- + // Helpers + // ---------------------------------------------------------------------- + + // any helper functions should go here or else delete this section + + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + + return { + ClassDeclaration(node) {} + } + } +} diff --git a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js new file mode 100644 index 000000000..fc3b6c7f5 --- /dev/null +++ b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js @@ -0,0 +1,93 @@ +/** + * @fileoverview ensure entity create - toJSON + * @creator david.lacedonia@adevinta.com + */ +'use strict' +const dedent = require('string-dedent') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'suggestion', + docs: { + description: 'ensure entity create - toJSON', + recommended: false, + url: null + }, + fixable: null, + schema: [], + messages: { + toJSONProperties: 'Missing toJSON properties ({{props}})', + invalidTOJSONProperties: 'toJSON should return an object', + missingToJSONMethod: dedent` + If your class has a 'static create' method. You have to define a 'toJSON' method too. + The output of the 'toJSON' should be the same as the input of your 'static create' method + `, + missingCreateMethod: dedent` + If your class has a 'toJSON' method. You have to define a 'static create' method too. + The output of the 'toJSON' should be the same as the input of your 'static create' method + ` + } + }, + + create(context) { + return { + ClassDeclaration(node) { + const create = node.body.body.find(i => i.key.name === 'create') + const toJSON = node.body.body.find(i => i.key.name === 'toJSON') + const className = node.id.name + + if (['UseCase', 'Service', 'Repository'].some(allowWord => className.includes(allowWord))) return // eslint-disable-line + + if (!create && !toJSON) return + + if (create && !toJSON) + return context.report({ + node: create, + messageId: 'missingToJSONMethod' + }) + + if (toJSON && !create) + return context.report({ + node: toJSON, + messageId: 'missingCreateMethod' + }) + + let createParams = create.value.params[0] || {properties: []} + if (createParams.left) { + createParams = createParams.left + } + + const createProperties = createParams.properties + const toJSONProperties = toJSON.value.body.body[0].argument.properties + + if (!toJSONProperties) { + return context.report({ + node: toJSON, + messageId: 'invalidTOJSONProperties' + }) + } + + const createProps = createProperties.map(i => i.key.name) + const toJSONProps = toJSONProperties.map(i => i.key.name) + + const missingToJSONProps = createProps.filter( + p => !toJSONProps.find(e => e === p) + ) + if (missingToJSONProps.length) { + context.report({ + node: toJSON, + messageId: 'toJSONProperties', + data: { + props: missingToJSONProps.join(', ') + } + }) + } + } + } + } +} diff --git a/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js b/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js new file mode 100644 index 000000000..e04d54faa --- /dev/null +++ b/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js @@ -0,0 +1,30 @@ +/** + * @fileoverview Ensure that our classes are using the convetion of has a static create method as factory. + * @author factory pattern + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ +import {RuleTester} from 'eslint' + +import rule from '../../../src/rules/factory-pattern' + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester() +ruleTester.run('factory-pattern', rule, { + valid: [ + // give me some code that won't trigger a warning + ], + + invalid: [ + { + code: "class Model { constructor() { this.name = 'John Doe' } }", + errors: [{message: 'Fill me in.', type: 'Me too'}] + } + ] +}) From c6ffa98cea6b262be5d203eaa91de5b82444aa46 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 7 Feb 2024 10:44:07 +0100 Subject: [PATCH 02/47] feat(packages/eslint-plugin-sui): make warning --- packages/eslint-plugin-sui/src/rules/factory-pattern.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin-sui/src/rules/factory-pattern.js b/packages/eslint-plugin-sui/src/rules/factory-pattern.js index 779da9890..97cf15290 100644 --- a/packages/eslint-plugin-sui/src/rules/factory-pattern.js +++ b/packages/eslint-plugin-sui/src/rules/factory-pattern.js @@ -13,7 +13,7 @@ const dedent = require('string-dedent') /** @type {import('eslint').Rule.RuleModule} */ module.exports = { meta: { - type: 'problem', + type: 'warning', docs: { description: 'ensure to define at least one factory function', recommended: true, @@ -54,7 +54,7 @@ module.exports = { ) if (!hasStaticFactoryMethod) { - return context.report({ + context.report({ node, messageId: 'notFoundFactoryFunction' }) From 0a2563ee0809c2e348684fdf72134cdc085e6060 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 7 Feb 2024 10:46:01 +0100 Subject: [PATCH 03/47] feat(packages/sui-lint): Create reporter flag --- packages/sui-lint/bin/sui-lint-js.js | 13 +++++++++-- packages/sui-lint/eslintrc.js | 20 ++++++++++++----- packages/sui-lint/package.json | 3 ++- packages/sui-lint/src/reporter.js | 32 ++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 packages/sui-lint/src/reporter.js diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index 4e2f90642..bf7db12fc 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -7,20 +7,23 @@ const {checkFilesToLint, getFilesToLint, getGitIgnoredFiles, stageFilesIfRequire const {ESLint} = require('eslint') const config = require('../eslintrc.js') +const {Reporter} = require('../src/reporter.js') program .option('--add-fixes') .option('--staged') .option('--fix', 'fix automatically problems with js files') .option('--ignore-patterns ', 'Path patterns to ignore for linting') + .option('--report', 'Send results to DD using sui-logger') + .option('--pattern ', 'Send results to DD using sui-logger') .parse(process.argv) -const {addFixes, fix, ignorePatterns = [], staged} = program.opts() +const {addFixes, fix, ignorePatterns = [], staged, pattern, report} = program.opts() const {CI} = process.env const EXTENSIONS = ['js', 'jsx', 'ts', 'tsx'] const IGNORE_PATTERNS = ['lib', 'dist', 'public', 'node_modules'] -const DEFAULT_PATTERN = './' +const DEFAULT_PATTERN = pattern ?? './' const LINT_FORMATTER = 'stylish' const baseConfig = { ...config, @@ -51,6 +54,12 @@ const baseConfig = { const results = await eslint.lintFiles(files) + if (report) { + debugger + console.log('[sui-lint] Generating report and send it to DD') + Reporter.create().map(results) + } + if (fix) { await ESLint.outputFixes(results) stageFilesIfRequired({extensions: EXTENSIONS, staged, addFixes}) diff --git a/packages/sui-lint/eslintrc.js b/packages/sui-lint/eslintrc.js index c247117c7..b4352b11c 100644 --- a/packages/sui-lint/eslintrc.js +++ b/packages/sui-lint/eslintrc.js @@ -175,7 +175,8 @@ module.exports = { 'react-hooks', 'simple-import-sort', 'jest', - 'jest-dom' + 'jest-dom', + 'sui' ], rules: { ...REACT_RULES, @@ -198,19 +199,28 @@ module.exports = { 'prefer-regex-literals': RULES.WARNING, 'prettier/prettier': [RULES.ERROR, prettierOptions], 'simple-import-sort/imports': [RULES.WARNING, {groups: IMPORT_SORT_GROUPS}], - 'react/jsx-no-bind': RULES.OFF + 'react/jsx-no-bind': RULES.OFF, + 'sui/factory-pattern': RULES.ERROR, + 'sui/serialize-deserialize': RULES.ERROR }, overrides: [ { files: ['**/*.+(ts|tsx)'], - extends: ['standard-with-typescript'], + extends: ['standard-with-typescript', 'standard-react', 'prettier'], + parser: '@typescript-eslint/parser', parserOptions: { project: './tsconfig.json' }, rules: { + 'import/extensions': RULES.OFF, 'no-return-await': RULES.OFF, - 'prettier/prettier': RULES.OFF, - 'react/react-in-jsx-scope': RULES.OFF + 'prettier/prettier': [RULES.ERROR, prettierOptions], + 'react/react-in-jsx-scope': RULES.OFF, + 'react/no-unused-prop-types': RULES.OFF, + '@typescript-eslint/explicit-function-return-type': [RULES.OFF, {allowTypedFunctionExpressions: false}], + 'chai-friendly/no-unused-expressions': RULES.ERROR, + '@typescript-eslint/no-unused-expressions': RULES.OFF, + '@typescript-eslint/return-await': RULES.OFF } }, { diff --git a/packages/sui-lint/package.json b/packages/sui-lint/package.json index dfb8672e4..aa29378b1 100644 --- a/packages/sui-lint/package.json +++ b/packages/sui-lint/package.json @@ -19,8 +19,9 @@ "@babel/eslint-plugin": "7.18.10", "@s-ui/helpers": "1", "@typescript-eslint/eslint-plugin": "5.62.0", + "@adv-ui/logger": "2", "commander": "8.3.0", - "eslint": "8.20.0", + "eslint": "8.56.0", "eslint-config-prettier": "8.5.0", "eslint-config-standard": "17.0.0", "eslint-config-standard-with-typescript": "22.0.0", diff --git a/packages/sui-lint/src/reporter.js b/packages/sui-lint/src/reporter.js new file mode 100644 index 000000000..841fd31ff --- /dev/null +++ b/packages/sui-lint/src/reporter.js @@ -0,0 +1,32 @@ +class Reporter { + #data + + static create() { + return new Reporter() + } + + map(results) { + const stats = results.reduce((rulesIDs, entry) => { + const repitedRulesFailed = entry.messages.map(message => message.ruleId) + const rulesFailed = new Set([...repitedRulesFailed]) + + rulesFailed.forEach(rule => { + rulesIDs[rule] = rulesIDs[rule] ?? [] + rulesIDs[rule].push(entry.filePath) + }) + return rulesIDs + }, {}) + + this.#data = { + totalFiles: results.length, + ...stats + } + debugger + } + + toJSON() { + return {} + } +} + +module.exports.Reporter = Reporter From e2cef862c94d6c0e8d8ea3f67df5e33a1dbaa6ae Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 7 Feb 2024 10:47:22 +0100 Subject: [PATCH 04/47] feat(packages/eslint-plugin-sui): add empty rule --- .../src/rules/function-named-parameters.js | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 packages/eslint-plugin-sui/src/rules/function-named-parameters.js diff --git a/packages/eslint-plugin-sui/src/rules/function-named-parameters.js b/packages/eslint-plugin-sui/src/rules/function-named-parameters.js new file mode 100644 index 000000000..99c991176 --- /dev/null +++ b/packages/eslint-plugin-sui/src/rules/function-named-parameters.js @@ -0,0 +1,47 @@ +/** + * @fileoverview Ensure that our function are using always named parameters + * @author factory pattern + */ +'use strict' + +const dedent = require('string-dedent') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'ensure to use named parameters', + recommended: true, + url: null + }, + fixable: null, + schema: [], + messages: { + badFileName: dedent``, + badClassName: dedent`` + } + }, + create: function (context) { + // variables should be defined here + + // ---------------------------------------------------------------------- + // Helpers + // ---------------------------------------------------------------------- + + // any helper functions should go here or else delete this section + + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + + return { + ClassDeclaration(node) {} + } + } +} + From 1ce2585af0a11d9dd11a21fc9cd9e7366a3122c3 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Tue, 13 Feb 2024 14:48:21 +0100 Subject: [PATCH 05/47] feat(packages/sui-lint): Add send method to the reporter --- packages/sui-lint/bin/sui-lint-js.js | 2 +- packages/sui-lint/package.json | 2 +- packages/sui-lint/src/reporter.js | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index bf7db12fc..87148995e 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -57,7 +57,7 @@ const baseConfig = { if (report) { debugger console.log('[sui-lint] Generating report and send it to DD') - Reporter.create().map(results) + await Reporter.create().map(results).send() } if (fix) { diff --git a/packages/sui-lint/package.json b/packages/sui-lint/package.json index aa29378b1..3df0fb71b 100644 --- a/packages/sui-lint/package.json +++ b/packages/sui-lint/package.json @@ -14,12 +14,12 @@ "author": "", "license": "MIT", "dependencies": { + "@adv-ui/logger": "^2.14.0", "@babel/core": "7.18.10", "@babel/eslint-parser": "7.18.9", "@babel/eslint-plugin": "7.18.10", "@s-ui/helpers": "1", "@typescript-eslint/eslint-plugin": "5.62.0", - "@adv-ui/logger": "2", "commander": "8.3.0", "eslint": "8.56.0", "eslint-config-prettier": "8.5.0", diff --git a/packages/sui-lint/src/reporter.js b/packages/sui-lint/src/reporter.js index 841fd31ff..6ee4cde63 100644 --- a/packages/sui-lint/src/reporter.js +++ b/packages/sui-lint/src/reporter.js @@ -21,7 +21,13 @@ class Reporter { totalFiles: results.length, ...stats } - debugger + } + + send() { + if(this.#data === undefined){ + throw new Error('[sui-lint] No data to send. Maybe you must call to map before') + } + } toJSON() { From 7d34092f0c083bdb8daefb3c254603196839b7b2 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 14 Feb 2024 12:17:13 +0100 Subject: [PATCH 06/47] feat(packages/sui-lint): Add send method to the reporter --- packages/sui-lint/bin/sui-lint-js.js | 1 - packages/sui-lint/src/reporter.js | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index 87148995e..970e0070f 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -55,7 +55,6 @@ const baseConfig = { const results = await eslint.lintFiles(files) if (report) { - debugger console.log('[sui-lint] Generating report and send it to DD') await Reporter.create().map(results).send() } diff --git a/packages/sui-lint/src/reporter.js b/packages/sui-lint/src/reporter.js index 6ee4cde63..3304667fc 100644 --- a/packages/sui-lint/src/reporter.js +++ b/packages/sui-lint/src/reporter.js @@ -1,6 +1,8 @@ class Reporter { #data + static RULES_TO_SEND = ['sui/'] + static create() { return new Reporter() } @@ -21,12 +23,25 @@ class Reporter { totalFiles: results.length, ...stats } + + return this } send() { if(this.#data === undefined){ throw new Error('[sui-lint] No data to send. Maybe you must call to map before') } + debugger + const {totalFiles, ...rest} = this.#data + const statsEntries = Object.entries(rest).map(entry => { + const [rule, failedFiles] = entry + if(!Reporter.RULES_TO_SEND.some(whiteRule => rule.startsWith(whiteRule))) return false + + return [rule, (failedFiles.length * 100) / totalFiles] + }).filter(Boolean) + + debugger + const stats = Object.fromEntries(statsEntries) } From ed4035f8b503c9c7eea41e762115fe4e6339ee51 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 28 Feb 2024 15:06:51 +0100 Subject: [PATCH 07/47] feat(packages/sui-lint): Create RepositoryLinter and desactivate eslint-preset-sui rules --- packages/sui-lint/bin/sui-lint-js.js | 15 ++-- packages/sui-lint/bin/sui-lint-repository.js | 36 ++++++++++ packages/sui-lint/eslintrc.js | 23 +++---- packages/sui-lint/package.json | 4 +- packages/sui-lint/repository.config.js | 15 ++++ .../sui-lint/src/RepositoryLinter/Config.js | 23 +++++++ .../sui-lint/src/RepositoryLinter/Context.js | 68 +++++++++++++++++++ .../sui-lint/src/RepositoryLinter/Match.js | 36 ++++++++++ .../sui-lint/src/RepositoryLinter/Results.js | 60 ++++++++++++++++ .../sui-lint/src/RepositoryLinter/Runner.js | 13 ++++ .../sui-lint/src/RepositoryLinter/index.js | 24 +++++++ packages/sui-lint/src/reporter.js | 53 --------------- 12 files changed, 294 insertions(+), 76 deletions(-) create mode 100755 packages/sui-lint/bin/sui-lint-repository.js create mode 100644 packages/sui-lint/repository.config.js create mode 100644 packages/sui-lint/src/RepositoryLinter/Config.js create mode 100644 packages/sui-lint/src/RepositoryLinter/Context.js create mode 100644 packages/sui-lint/src/RepositoryLinter/Match.js create mode 100644 packages/sui-lint/src/RepositoryLinter/Results.js create mode 100644 packages/sui-lint/src/RepositoryLinter/Runner.js create mode 100644 packages/sui-lint/src/RepositoryLinter/index.js delete mode 100644 packages/sui-lint/src/reporter.js diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index 970e0070f..7a566d15a 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -7,18 +7,17 @@ const {checkFilesToLint, getFilesToLint, getGitIgnoredFiles, stageFilesIfRequire const {ESLint} = require('eslint') const config = require('../eslintrc.js') -const {Reporter} = require('../src/reporter.js') program .option('--add-fixes') .option('--staged') .option('--fix', 'fix automatically problems with js files') .option('--ignore-patterns ', 'Path patterns to ignore for linting') - .option('--report', 'Send results to DD using sui-logger') - .option('--pattern ', 'Send results to DD using sui-logger') + .option('--reporter ', 'Send results to DD using sui-logger') + .option('--pattern ', 'Patter of files to lint') .parse(process.argv) -const {addFixes, fix, ignorePatterns = [], staged, pattern, report} = program.opts() +const {addFixes, fix, ignorePatterns = [], staged, pattern, reporter} = program.opts() const {CI} = process.env const EXTENSIONS = ['js', 'jsx', 'ts', 'tsx'] @@ -54,9 +53,11 @@ const baseConfig = { const results = await eslint.lintFiles(files) - if (report) { - console.log('[sui-lint] Generating report and send it to DD') - await Reporter.create().map(results).send() + if (reporter) { + console.log('[sui-lint] Sending stats using the reporter ', reporter) + const {Reporter} = await import(reporter) + const reportered = await Reporter.create() + await reportered.map(results).send() } if (fix) { diff --git a/packages/sui-lint/bin/sui-lint-repository.js b/packages/sui-lint/bin/sui-lint-repository.js new file mode 100755 index 000000000..e8d845225 --- /dev/null +++ b/packages/sui-lint/bin/sui-lint-repository.js @@ -0,0 +1,36 @@ +#!/usr/bin/env node +/* eslint-disable no-console */ + +const program = require('commander') +const {RepositoryLinter} = require('../src/RepositoryLinter') + +program + .option('--reporter ', 'Send results to DD using sui-logger') + .option('--output-json ', 'Print messages errors as JSON. Default is a table') + .parse(process.argv) + +const {reporter, outputJson} = program.opts() + +;(async function main() { + const linter = RepositoryLinter.create() + const results = await linter.lint() + + if (outputJson) console.log('\n\n') + if (outputJson) { + results.logJSON() + } else { + results.logTable() + } + if (outputJson) console.log('\n\n') + + if (reporter) { + console.log('\n[sui-lint] Sending stats using the reporter\n\n', reporter) + const {RepositoryReporter} = await import(reporter) + const reportered = RepositoryReporter.create() + await reportered.map(results).send() + results.logMonitorings() + } +})().catch(error => { + process.exitCode = 1 + console.error('[sui-lint]', error) +}) diff --git a/packages/sui-lint/eslintrc.js b/packages/sui-lint/eslintrc.js index b4352b11c..7f089f0e2 100644 --- a/packages/sui-lint/eslintrc.js +++ b/packages/sui-lint/eslintrc.js @@ -175,8 +175,8 @@ module.exports = { 'react-hooks', 'simple-import-sort', 'jest', - 'jest-dom', - 'sui' + 'jest-dom' + // 'sui' ], rules: { ...REACT_RULES, @@ -199,28 +199,21 @@ module.exports = { 'prefer-regex-literals': RULES.WARNING, 'prettier/prettier': [RULES.ERROR, prettierOptions], 'simple-import-sort/imports': [RULES.WARNING, {groups: IMPORT_SORT_GROUPS}], - 'react/jsx-no-bind': RULES.OFF, - 'sui/factory-pattern': RULES.ERROR, - 'sui/serialize-deserialize': RULES.ERROR + 'react/jsx-no-bind': RULES.OFF + // 'sui/factory-pattern': RULES.ERROR, + // 'sui/serialize-deserialize': RULES.ERROR }, overrides: [ { files: ['**/*.+(ts|tsx)'], - extends: ['standard-with-typescript', 'standard-react', 'prettier'], - parser: '@typescript-eslint/parser', + extends: ['standard-with-typescript'], parserOptions: { project: './tsconfig.json' }, rules: { - 'import/extensions': RULES.OFF, 'no-return-await': RULES.OFF, - 'prettier/prettier': [RULES.ERROR, prettierOptions], - 'react/react-in-jsx-scope': RULES.OFF, - 'react/no-unused-prop-types': RULES.OFF, - '@typescript-eslint/explicit-function-return-type': [RULES.OFF, {allowTypedFunctionExpressions: false}], - 'chai-friendly/no-unused-expressions': RULES.ERROR, - '@typescript-eslint/no-unused-expressions': RULES.OFF, - '@typescript-eslint/return-await': RULES.OFF + 'prettier/prettier': RULES.OFF, + 'react/react-in-jsx-scope': RULES.OFF } }, { diff --git a/packages/sui-lint/package.json b/packages/sui-lint/package.json index 3df0fb71b..619497be1 100644 --- a/packages/sui-lint/package.json +++ b/packages/sui-lint/package.json @@ -14,13 +14,15 @@ "author": "", "license": "MIT", "dependencies": { - "@adv-ui/logger": "^2.14.0", "@babel/core": "7.18.10", "@babel/eslint-parser": "7.18.9", "@babel/eslint-plugin": "7.18.10", "@s-ui/helpers": "1", "@typescript-eslint/eslint-plugin": "5.62.0", "commander": "8.3.0", + "console-table-printer": "2.12.0", + "js-yaml": "4.1.0", + "fast-glob": "3.3.2", "eslint": "8.56.0", "eslint-config-prettier": "8.5.0", "eslint-config-standard": "17.0.0", diff --git a/packages/sui-lint/repository.config.js b/packages/sui-lint/repository.config.js new file mode 100644 index 000000000..a4f0bf935 --- /dev/null +++ b/packages/sui-lint/repository.config.js @@ -0,0 +1,15 @@ +const RULES = { + OFF: 0, + WARNING: 1, + ERROR: 2 +} + +module.exports = { + plugins: ['sui'], + rules: { + 'sui/node-version': RULES.WARNING, + 'sui/react-version': RULES.WARNING, + 'sui/package-lock': RULES.WARNING, + 'sui/github-action': RULES.WARNING + } +} diff --git a/packages/sui-lint/src/RepositoryLinter/Config.js b/packages/sui-lint/src/RepositoryLinter/Config.js new file mode 100644 index 000000000..6def2e744 --- /dev/null +++ b/packages/sui-lint/src/RepositoryLinter/Config.js @@ -0,0 +1,23 @@ +module.exports.Config = class Config { + static create() { + return new Config() + } + + async load() { + const repositoryConfig = require('../../repository.config.js') + + const rules = repositoryConfig.plugins.reduce((acc, pkg) => { + const pkgConfig = require(`lint-repository-${pkg}`) + const rulesEntries = Object.entries(pkgConfig.rules) + .map(([rule, handler]) => { + const key = `${pkg}/${rule}` + const level = repositoryConfig.rules[key] + return level ? [key, {handler, level}] : [] + }) + .filter(([key, value]) => key && value) + return {...acc, ...Object.fromEntries(rulesEntries)} + }, {}) + + return rules + } +} diff --git a/packages/sui-lint/src/RepositoryLinter/Context.js b/packages/sui-lint/src/RepositoryLinter/Context.js new file mode 100644 index 000000000..72ceebb04 --- /dev/null +++ b/packages/sui-lint/src/RepositoryLinter/Context.js @@ -0,0 +1,68 @@ +const {Runner} = require('./Runner') + +const EMPTY = 0 + +module.exports.Context = class Context { + #messages = [] + #monitorings = [] + #handler + #runner + + static create(level, handler, rule) { + return new Context(level, handler, rule, Runner.create()) + } + + constructor(level, handler, rule, runner) { + this.#handler = handler + this.#runner = runner + this.rule = rule + this.level = level + } + + run() { + const assertions = this.#handler.create(this) + const {missmatch = () => {}, ...restAssertions} = assertions + Object.entries(restAssertions).forEach(([key, fn]) => { + const matches = this.#runner.assertion(key) + if (matches.length === EMPTY) { + this._assertion = 'missmatch' + return missmatch(key) + } + this._assertion = key // We cant execute assertions in parallel + fn(matches) + }) + return this + } + + get messages() { + return this.#messages.map(opts => { + let message = this.#handler?.meta?.messages[opts.messageId] ?? opts.messageId + message = Object.entries(opts.data ?? {}).reduce((acc, [key, value]) => { + return acc.replaceAll(`{{${key}}}`, value) + }, message) + return {...opts, message, rule: this.rule, level: this.level} + }) + } + + get signal() { + const _signal = {rule: this.rule, level: this.level} + if (this.#monitorings.length === 0) return _signal + if (this.#monitorings.length === 1) return {..._signal, value: this.#monitorings[0].value} + + if (this.#handler.reduceMonitoring === undefined) + throw new Error(` + [RepositoryLinter Context#signal] If your has call to 'context.monitoring' more than one time in your rule. + You have to create a function 'reduceMonitoring' to be able reduce all of them to 1 value. + `) + + return {rule: this.rule, level: this.level, value: this.#handler?.reduceMonitoring(this.#monitorings)} + } + + report(opts) { + this.#messages.push(opts) + } + + monitoring(value, assertion) { + this.#monitorings.push({assertion: assertion ?? this._assertion, rule: this.rule, value, level: this.level}) + } +} diff --git a/packages/sui-lint/src/RepositoryLinter/Match.js b/packages/sui-lint/src/RepositoryLinter/Match.js new file mode 100644 index 000000000..4dbd19ff5 --- /dev/null +++ b/packages/sui-lint/src/RepositoryLinter/Match.js @@ -0,0 +1,36 @@ +const {extname} = require('path') +const yaml = require('js-yaml') +const fs = require('fs') + +module.exports.Match = class Match { + static create(path) { + const ext = extname(path) + if (!ext && fs.statSync(process.cwd() + '/' + path).isDirectory()) { + return new Match(path, undefined, undefined, true) + } + + let parsed + let raw + switch (ext) { + case '.json': + parsed = require(process.cwd() + '/' + path) + break + case '.yml': + case '.yaml': + parsed = yaml.load(fs.readFileSync(process.cwd() + '/' + path, 'utf8')) + break + default: + raw = fs.readFileSync(process.cwd() + '/' + path, 'utf8') + } + + return new Match(path, parsed, raw, false) + } + + constructor(path, parsed, raw, isDir) { + this.parsed = parsed + this.raw = raw + this.path = path + this.isDir = isDir + this.fullPath = process.cwd() + '/' + path + } +} diff --git a/packages/sui-lint/src/RepositoryLinter/Results.js b/packages/sui-lint/src/RepositoryLinter/Results.js new file mode 100644 index 000000000..079ff3ba6 --- /dev/null +++ b/packages/sui-lint/src/RepositoryLinter/Results.js @@ -0,0 +1,60 @@ +const dedent = require('string-dedent') +const {Table} = require('console-table-printer') + +const COLORS_BY_LEVEL = ['green', 'yellow', 'red'] + +module.exports.Results = class Results { + #executions + #messages + #monitorings + + static create(executions) { + return new Results(executions) + } + + constructor(executions) { + this.#executions = executions + this.#messages = executions.reduce((acc, ctxt) => [...acc, ...ctxt.messages], []) + this.#monitorings = executions.map(ctxt => ctxt.signal) + } + + get monitorings() { + return this.#monitorings + } + + logTable() { + if (this.#messages.length === 0) + return console.log(dedent` + 🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳 + 🥳 Your repository follow all our internal conventions 🥳 + 🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳 + `) + + const p = new Table({ + title: dedent` + Lint Respository messages (green=OFF, yellow=WARNING, red=ERROR) + ` + }) + this.#messages.forEach(msg => + p.addRow({rule: msg.rule, message: msg.message.replaceAll('\n', ' ')}, {color: COLORS_BY_LEVEL[msg.level]}) + ) + p.printTable() + } + + logJSON() { + return console.log(JSON.stringify(this.#messages, null, 2)) + } + + logMonitorings() { + if (this.#monitorings.length === 0) + return console.log(dedent` + + There is not signal to be send to DD. Use 'context.monitoring' to add signals at your execution + + `) + + const p = new Table({title: 'List of Signals that will be send to DD'}) + this.#monitorings.forEach(monitor => p.addRow(monitor)) + p.printTable() + } +} diff --git a/packages/sui-lint/src/RepositoryLinter/Runner.js b/packages/sui-lint/src/RepositoryLinter/Runner.js new file mode 100644 index 000000000..056d3204f --- /dev/null +++ b/packages/sui-lint/src/RepositoryLinter/Runner.js @@ -0,0 +1,13 @@ +const {Match} = require('./Match') +const fg = require('fast-glob') + +module.exports.Runner = class Runner { + static create() { + return new Runner() + } + + assertion(key) { + const files = fg.sync(key, {ignore: ['node_modules'], onlyFiles: false}) ?? [] + return files.map(Match.create) + } +} diff --git a/packages/sui-lint/src/RepositoryLinter/index.js b/packages/sui-lint/src/RepositoryLinter/index.js new file mode 100644 index 000000000..0399abc92 --- /dev/null +++ b/packages/sui-lint/src/RepositoryLinter/index.js @@ -0,0 +1,24 @@ +const {Config} = require('./Config') +const {Context} = require('./Context') +const {Results} = require('./Results') + +module.exports.RepositoryLinter = class RepositoryLinter { + #cofig + + static create() { + return new RepositoryLinter(Config.create()) + } + + constructor(config) { + this.#cofig = config + } + + async lint() { + const rules = await this.#cofig.load() + const executions = Object.entries(rules).map(([rule, {handler, level}]) => + Context.create(level, handler, rule).run() + ) + + return Results.create(executions) + } +} diff --git a/packages/sui-lint/src/reporter.js b/packages/sui-lint/src/reporter.js deleted file mode 100644 index 3304667fc..000000000 --- a/packages/sui-lint/src/reporter.js +++ /dev/null @@ -1,53 +0,0 @@ -class Reporter { - #data - - static RULES_TO_SEND = ['sui/'] - - static create() { - return new Reporter() - } - - map(results) { - const stats = results.reduce((rulesIDs, entry) => { - const repitedRulesFailed = entry.messages.map(message => message.ruleId) - const rulesFailed = new Set([...repitedRulesFailed]) - - rulesFailed.forEach(rule => { - rulesIDs[rule] = rulesIDs[rule] ?? [] - rulesIDs[rule].push(entry.filePath) - }) - return rulesIDs - }, {}) - - this.#data = { - totalFiles: results.length, - ...stats - } - - return this - } - - send() { - if(this.#data === undefined){ - throw new Error('[sui-lint] No data to send. Maybe you must call to map before') - } - debugger - const {totalFiles, ...rest} = this.#data - const statsEntries = Object.entries(rest).map(entry => { - const [rule, failedFiles] = entry - if(!Reporter.RULES_TO_SEND.some(whiteRule => rule.startsWith(whiteRule))) return false - - return [rule, (failedFiles.length * 100) / totalFiles] - }).filter(Boolean) - - debugger - const stats = Object.fromEntries(statsEntries) - - } - - toJSON() { - return {} - } -} - -module.exports.Reporter = Reporter From 75a3684fed86de9d2f3ddaa06c94d6d641b26740 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 28 Feb 2024 15:07:36 +0100 Subject: [PATCH 08/47] refactor(packages/eslint-plugin-sui): eslint format --- .../eslint-plugin-sui/src/rules/function-named-parameters.js | 1 - packages/eslint-plugin-sui/src/rules/serialize-deserialize.js | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/eslint-plugin-sui/src/rules/function-named-parameters.js b/packages/eslint-plugin-sui/src/rules/function-named-parameters.js index 99c991176..d7fcd975a 100644 --- a/packages/eslint-plugin-sui/src/rules/function-named-parameters.js +++ b/packages/eslint-plugin-sui/src/rules/function-named-parameters.js @@ -44,4 +44,3 @@ module.exports = { } } } - diff --git a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js index fc3b6c7f5..82232e19a 100644 --- a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js +++ b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js @@ -75,9 +75,7 @@ module.exports = { const createProps = createProperties.map(i => i.key.name) const toJSONProps = toJSONProperties.map(i => i.key.name) - const missingToJSONProps = createProps.filter( - p => !toJSONProps.find(e => e === p) - ) + const missingToJSONProps = createProps.filter(p => !toJSONProps.find(e => e === p)) if (missingToJSONProps.length) { context.report({ node: toJSON, From 836098d30de4fe2f5420530bd10902d2d2d278cb Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 28 Feb 2024 15:08:50 +0100 Subject: [PATCH 09/47] feat(packages/lint-repository-sui): Create first version of the Golden Path Rules --- packages/lint-repository-sui/README.md | 0 packages/lint-repository-sui/package.json | 17 +++++ packages/lint-repository-sui/src/index.js | 18 +++++ .../src/rules/github-action.js | 71 +++++++++++++++++++ .../src/rules/node-version.js | 60 ++++++++++++++++ .../src/rules/package-lock.js | 34 +++++++++ .../src/rules/react-version.js | 62 ++++++++++++++++ 7 files changed, 262 insertions(+) create mode 100644 packages/lint-repository-sui/README.md create mode 100644 packages/lint-repository-sui/package.json create mode 100644 packages/lint-repository-sui/src/index.js create mode 100644 packages/lint-repository-sui/src/rules/github-action.js create mode 100644 packages/lint-repository-sui/src/rules/node-version.js create mode 100644 packages/lint-repository-sui/src/rules/package-lock.js create mode 100644 packages/lint-repository-sui/src/rules/react-version.js diff --git a/packages/lint-repository-sui/README.md b/packages/lint-repository-sui/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/packages/lint-repository-sui/package.json b/packages/lint-repository-sui/package.json new file mode 100644 index 000000000..97c8dbcb5 --- /dev/null +++ b/packages/lint-repository-sui/package.json @@ -0,0 +1,17 @@ +{ + "name": "lint-repository-sui", + "version": "0.0.0", + "description": "Set of sui lint rules to lint a repository", + "keywords": [ + ], + "author": "Sui", + "main": "./src/index.js", + "exports": "./src/index.js", + "scripts": { + }, + "dependencies": { + }, + "devDependencies": { + } +} + diff --git a/packages/lint-repository-sui/src/index.js b/packages/lint-repository-sui/src/index.js new file mode 100644 index 000000000..3ec72031b --- /dev/null +++ b/packages/lint-repository-sui/src/index.js @@ -0,0 +1,18 @@ +const NodeVersion = require('./rules/node-version.js') +const ReactVersion = require('./rules/react-version.js') +const PackageLock = require('./rules/package-lock.js') +const GithubAction = require('./rules/github-action.js') + +// ------------------------------------------------------------------------------ +// Plugin Definition +// ------------------------------------------------------------------------------ + +// import all rules in lib/rules +module.exports = { + rules: { + 'node-version': NodeVersion, + 'react-version': ReactVersion, + 'package-lock': PackageLock, + 'github-action': GithubAction + } +} diff --git a/packages/lint-repository-sui/src/rules/github-action.js b/packages/lint-repository-sui/src/rules/github-action.js new file mode 100644 index 000000000..402f83a5a --- /dev/null +++ b/packages/lint-repository-sui/src/rules/github-action.js @@ -0,0 +1,71 @@ +const dedent = require('string-dedent') + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Check that your repository have properly setup the GHA to CI/CD', + recommended: true, + url: null + }, + fixable: null, + schema: [], + messages: { + missingGithubFolder: dedent` + Every project needs to have a .github/worflows folder to be able to run CI/CD in GHA. + If you are not sure about how do it, please contact with Platform Web. + `, + missingMainWorkflow: dedent` + Every project needs to have a workflow to run on master. + If you are not sure about how do it, please contact with Platform Web. + `, + missingPRWorkflow: dedent` + Every project needs to have a workflow to run on every PR. + If you are not sure about how do it, please contact with Platform Web. + ` + } + }, + reduceMonitoring: function (monitorings) { + return monitorings.reduce((acc, signal) => { + return acc && signal.value + }, true) + }, + create: function (context) { + return { + '.github/_workflows': matches => { + context.monitoring(true) + }, + + '.github/**/main.yml': matches => { + context.monitoring(true) + }, + + '.github/**/pullrequest.yml': matches => { + context.monitoring(true) + }, + + missmatch: key => { + if (key === '.github/_workflows') { + context.report({ + messageId: 'missingGithubFolder' + }) + context.monitoring(false, '.github/workflows') + } + + if (key === '.github/**/main.yml') { + context.report({ + messageId: 'missingMainWorkflow' + }) + context.monitoring(false, '.github/**/main.yml') + } + + if (key === '.github/**/pullrequest.yml') { + context.report({ + messageId: 'missingPRWorkflow' + }) + context.monitoring(false, '.github/**/pullrequest.yml') + } + } + } + } +} diff --git a/packages/lint-repository-sui/src/rules/node-version.js b/packages/lint-repository-sui/src/rules/node-version.js new file mode 100644 index 000000000..0e53b0f68 --- /dev/null +++ b/packages/lint-repository-sui/src/rules/node-version.js @@ -0,0 +1,60 @@ +const dedent = require('string-dedent') + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Check that your repository use the latest Node version', + recommended: true, + url: null + }, + fixable: null, + schema: [], + messages: { + moreThanOneNVMRC: dedent` + Your project has more than one .nvmrc file. That can be dangerous. + Please, use onle ONE in the root of your project. + If you are not sure about how do it, please contact with Platform Web. + `, + badNodeVersion: dedent` + Your current Node version is {{version}}. + Please be sure that your repository use the latest Node Version 20. + If you are not sure about how do it, please contact with Platform Web. + `, + noNMVRCFile: dedent` + Every project have to have a .npmrc file to define the node versión. + If you are not sure about how do it, please contact with Platform Web. + ` + } + }, + create: function (context) { + return { + '.nvmrc': matches => { + if (matches.length > 1) { + context.report({ + messageId: 'moreThanOneNVMRC' + }) + return context.monitoring(0) + } + + const [nvmrcMatch] = matches + const version = nvmrcMatch.raw.trim() + if (version !== '20') { + context.report({ + messageId: 'badNodeVersion', + data: {version} + }) + } + + context.monitoring(version) + }, + + missmatch: key => { + context.report({ + messageId: 'noNMVRCFile' + }) + context.monitoring(0) + } + } + } +} diff --git a/packages/lint-repository-sui/src/rules/package-lock.js b/packages/lint-repository-sui/src/rules/package-lock.js new file mode 100644 index 000000000..657fdaca0 --- /dev/null +++ b/packages/lint-repository-sui/src/rules/package-lock.js @@ -0,0 +1,34 @@ +const dedent = require('string-dedent') + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Check that your repository have created a package-lock file', + recommended: true, + url: null + }, + fixable: null, + schema: [], + messages: { + missingPackageLock: dedent` + Every project needs to have a package-lock.json file to be used in CI/CD. + If you are not sure about how do it, please contact with Platform Web. + ` + } + }, + create: function (context) { + return { + 'package-lock.json': matches => { + context.monitoring(true) + }, + + missmatch: key => { + context.report({ + messageId: 'missingPackageLock' + }) + context.monitoring(false) + } + } + } +} diff --git a/packages/lint-repository-sui/src/rules/react-version.js b/packages/lint-repository-sui/src/rules/react-version.js new file mode 100644 index 000000000..38411eb7f --- /dev/null +++ b/packages/lint-repository-sui/src/rules/react-version.js @@ -0,0 +1,62 @@ +const dedent = require('string-dedent') + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Check that your repository use the latest React version', + recommended: true, + url: null + }, + fixable: null, + schema: [], + messages: { + badReactVersion: dedent` + Please be sure that your repository use the latest React Version 18. + Your current version is {{version}}. + If you are not sure about how do it, please contact with Platform Web. + `, + missingReactDependencie: dedent` + Your project doesnt have installed React. + Please install at least the version 18. + If you are not sure about how do it, please contact with Platform Web. + `, + missingPackageLock: dedent` + To calculate the react version first we need to have a package-lock.json in the root + If you are not sure about how do it, please contact with Platform Web. + ` + } + }, + create: function (context) { + return { + 'package-lock.json': matches => { + const [packageLock] = matches + let version = packageLock?.parsed?.packages?.['node_modules/react']?.version + + if (!version) { + context.report({ + messageId: 'missingReactDependencie' + }) + return context.monitoring(0) + } + + version = version.split('.')[0] + + if (version !== '18') { + context.report({ + messageId: 'badReactVersion', + data: {version} + }) + } + return context.monitoring(version) + }, + + missmatch: key => { + context.report({ + messageId: 'missingPackageLock' + }) + context.monitoring(0) + } + } + } +} From 07293da8db0823911b3a6f7518d5de4fc1cbf24d Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 28 Feb 2024 15:47:50 +0100 Subject: [PATCH 10/47] fix(packages/sui-lint): Fix JSReporter import and plugins version --- packages/sui-lint/bin/sui-lint-js.js | 4 ++-- packages/sui-lint/bin/sui-lint.js | 2 +- packages/sui-lint/package.json | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index 7a566d15a..91a826d04 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -55,8 +55,8 @@ const baseConfig = { if (reporter) { console.log('[sui-lint] Sending stats using the reporter ', reporter) - const {Reporter} = await import(reporter) - const reportered = await Reporter.create() + const {JSReporter} = await import(reporter) + const reportered = await JSReporter.create() await reportered.map(results).send() } diff --git a/packages/sui-lint/bin/sui-lint.js b/packages/sui-lint/bin/sui-lint.js index 78c90c0aa..61623f84c 100755 --- a/packages/sui-lint/bin/sui-lint.js +++ b/packages/sui-lint/bin/sui-lint.js @@ -4,6 +4,6 @@ const {version} = require('../package.json') program.version(version, ' --version') -program.command('js', 'lint javascript files').command('sass', 'lint sass files') +program.command('js', 'lint javascript files').command('sass', 'lint sass files').command('repository', 'lint repository structure') program.parse(process.argv) diff --git a/packages/sui-lint/package.json b/packages/sui-lint/package.json index 619497be1..1839a1dbe 100644 --- a/packages/sui-lint/package.json +++ b/packages/sui-lint/package.json @@ -39,6 +39,8 @@ "eslint-plugin-react": "7.30.1", "eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-simple-import-sort": "7.0.0", + "eslint-plugin-sui": "1", + "lint-repository-sui": "1", "postcss-scss": "4.0.4", "prettier": "2.7.1", "stylelint": "14.11.0", From 36a3830f0d0056d0dbc01dbd526ce8261fdb723d Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 28 Feb 2024 16:01:07 +0100 Subject: [PATCH 11/47] fix(packages/lint-repository-sui): Fix typo in rule --- packages/lint-repository-sui/src/rules/github-action.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lint-repository-sui/src/rules/github-action.js b/packages/lint-repository-sui/src/rules/github-action.js index 402f83a5a..5ace0db38 100644 --- a/packages/lint-repository-sui/src/rules/github-action.js +++ b/packages/lint-repository-sui/src/rules/github-action.js @@ -32,7 +32,7 @@ module.exports = { }, create: function (context) { return { - '.github/_workflows': matches => { + '.github/workflows': matches => { context.monitoring(true) }, @@ -45,7 +45,7 @@ module.exports = { }, missmatch: key => { - if (key === '.github/_workflows') { + if (key === '.github/workflows') { context.report({ messageId: 'missingGithubFolder' }) From 02cd409e73ac28dc21bda52c1229adcde74fc28d Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 28 Feb 2024 16:04:21 +0100 Subject: [PATCH 12/47] fix(packages/sui-lint): Fix version --- packages/sui-lint/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sui-lint/package.json b/packages/sui-lint/package.json index 1839a1dbe..9f4181b1e 100644 --- a/packages/sui-lint/package.json +++ b/packages/sui-lint/package.json @@ -39,8 +39,8 @@ "eslint-plugin-react": "7.30.1", "eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-simple-import-sort": "7.0.0", - "eslint-plugin-sui": "1", - "lint-repository-sui": "1", + "eslint-plugin-sui": "beta", + "lint-repository-sui": "beta", "postcss-scss": "4.0.4", "prettier": "2.7.1", "stylelint": "14.11.0", From e0fd01378a1f3c381d99802d1feb827d55f0eae3 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 28 Feb 2024 16:15:01 +0100 Subject: [PATCH 13/47] fix(packages/sui-lint): Fix lint --- packages/sui-lint/bin/sui-lint.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/sui-lint/bin/sui-lint.js b/packages/sui-lint/bin/sui-lint.js index 61623f84c..1f2816297 100755 --- a/packages/sui-lint/bin/sui-lint.js +++ b/packages/sui-lint/bin/sui-lint.js @@ -4,6 +4,8 @@ const {version} = require('../package.json') program.version(version, ' --version') -program.command('js', 'lint javascript files').command('sass', 'lint sass files').command('repository', 'lint repository structure') +program.command('js', 'lint javascript files') + .command('sass', 'lint sass files') + .command('repository', 'lint repository structure') program.parse(process.argv) From 0836810202a370e600fd1cb25250a18595aa7e81 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Wed, 28 Feb 2024 16:31:01 +0100 Subject: [PATCH 14/47] fix(packages/sui-lint): Fix lint --- packages/sui-lint/bin/sui-lint.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/sui-lint/bin/sui-lint.js b/packages/sui-lint/bin/sui-lint.js index 1f2816297..12bd4bbb9 100755 --- a/packages/sui-lint/bin/sui-lint.js +++ b/packages/sui-lint/bin/sui-lint.js @@ -4,7 +4,8 @@ const {version} = require('../package.json') program.version(version, ' --version') -program.command('js', 'lint javascript files') +program + .command('js', 'lint javascript files') .command('sass', 'lint sass files') .command('repository', 'lint repository structure') From 74751db22552649b6cfb94410c7e4be3194200ed Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Fri, 1 Mar 2024 12:09:57 +0100 Subject: [PATCH 15/47] test(packages/eslint-plugin-sui): Add more tests --- packages/eslint-plugin-sui/package.json | 3 +- .../tests/src/rules/factory-pattern.js | 37 ++++--- .../tests/src/rules/serialize-deserialize.js | 96 +++++++++++++++++++ 3 files changed, 122 insertions(+), 14 deletions(-) create mode 100644 packages/eslint-plugin-sui/tests/src/rules/serialize-deserialize.js diff --git a/packages/eslint-plugin-sui/package.json b/packages/eslint-plugin-sui/package.json index 99d36c4a1..bb67458ac 100644 --- a/packages/eslint-plugin-sui/package.json +++ b/packages/eslint-plugin-sui/package.json @@ -14,7 +14,7 @@ "lint": "npm-run-all \"lint:*\"", "lint:eslint-docs": "npm-run-all \"update:eslint-docs -- --check\"", "lint:js": "eslint .", - "test": "mocha tests --recursive", + "test": "npx sui-test server -P ./tests/**/*.js", "update:eslint-docs": "eslint-doc-generator" }, "dependencies": { @@ -22,6 +22,7 @@ "string-dedent": "^3.0.1" }, "devDependencies": { + "@s-ui/test": "^8.33.0", "eslint": "^8.19.0", "eslint-doc-generator": "^1.0.0", "eslint-plugin-eslint-plugin": "^5.0.0", diff --git a/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js b/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js index e04d54faa..9f961d232 100644 --- a/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js +++ b/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js @@ -1,30 +1,41 @@ -/** - * @fileoverview Ensure that our classes are using the convetion of has a static create method as factory. - * @author factory pattern - */ -'use strict' - -// ------------------------------------------------------------------------------ -// Requirements -// ------------------------------------------------------------------------------ +import dedent from 'dedent' import {RuleTester} from 'eslint' import rule from '../../../src/rules/factory-pattern' // ------------------------------------------------------------------------------ // Tests +// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester // ------------------------------------------------------------------------------ -const ruleTester = new RuleTester() +const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) ruleTester.run('factory-pattern', rule, { valid: [ - // give me some code that won't trigger a warning + { + code: dedent` + class User { + static create() { return new User() } + } + ` + } ], invalid: [ { - code: "class Model { constructor() { this.name = 'John Doe' } }", - errors: [{message: 'Fill me in.', type: 'Me too'}] + code: dedent` + class Model { + constructor() { this.name = 'John Doe' } + }`, + errors: [ + { + message: dedent` + You have to define at least one static function that return an instance of your class. + Avoid to use the 'new' keyword directly in your code. + Use always a factory function + `, + type: 'ClassDeclaration' + } + ] } ] }) diff --git a/packages/eslint-plugin-sui/tests/src/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/tests/src/rules/serialize-deserialize.js new file mode 100644 index 000000000..b9d952b68 --- /dev/null +++ b/packages/eslint-plugin-sui/tests/src/rules/serialize-deserialize.js @@ -0,0 +1,96 @@ +import dedent from 'dedent' +import {RuleTester} from 'eslint' + +import rule from '../../../src/rules/serialize-deserialize' + +// ------------------------------------------------------------------------------ +// Tests +// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) +ruleTester.run('serialize-deserialize', rule, { + valid: [ + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + id: this.id, + name: this.name + } + } + } + ` + } + ], + + invalid: [ + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return this.id + } + } + `, + errors: [ + { + message: dedent`toJSON should return an object` + } + ] + }, + { + code: dedent` + class User { + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + Noid: this.id, + Noname: this.name + } + } + } + `, + errors: [ + { + message: dedent` + If your class has a 'toJSON' method. You have to define a 'static create' method too. + The output of the 'toJSON' should be the same as the input of your 'static create' method + ` + } + ] + }, + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + Noid: this.id, + Noname: this.name + } + } + } + `, + errors: [{message: 'Missing toJSON properties (id, name)'}] + } + ] +}) From d057f605e68a921a8018c790e7b76d3e94afbdde Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Fri, 1 Mar 2024 12:11:53 +0100 Subject: [PATCH 16/47] test(packages/lint-repository-sui): Add firsts tests Create a custom test runner following the ESLint API --- packages/lint-repository-sui/package.json | 8 +-- .../lint-repository-sui/test/TestHelpers.js | 64 +++++++++++++++++++ .../test/rules/github-actionSpec.js | 53 +++++++++++++++ .../test/rules/node-versionSpec.js | 44 +++++++++++++ .../test/rules/package-lockSpec.js | 25 ++++++++ .../test/rules/react-versionSpec.js | 44 +++++++++++++ 6 files changed, 233 insertions(+), 5 deletions(-) create mode 100644 packages/lint-repository-sui/test/TestHelpers.js create mode 100644 packages/lint-repository-sui/test/rules/github-actionSpec.js create mode 100644 packages/lint-repository-sui/test/rules/node-versionSpec.js create mode 100644 packages/lint-repository-sui/test/rules/package-lockSpec.js create mode 100644 packages/lint-repository-sui/test/rules/react-versionSpec.js diff --git a/packages/lint-repository-sui/package.json b/packages/lint-repository-sui/package.json index 97c8dbcb5..46455cfa6 100644 --- a/packages/lint-repository-sui/package.json +++ b/packages/lint-repository-sui/package.json @@ -2,16 +2,14 @@ "name": "lint-repository-sui", "version": "0.0.0", "description": "Set of sui lint rules to lint a repository", - "keywords": [ - ], + "keywords": [], "author": "Sui", "main": "./src/index.js", "exports": "./src/index.js", "scripts": { - }, - "dependencies": { + "test": "npx sui-test server" }, "devDependencies": { + "@s-ui/test": "^8.33.0" } } - diff --git a/packages/lint-repository-sui/test/TestHelpers.js b/packages/lint-repository-sui/test/TestHelpers.js new file mode 100644 index 000000000..ce34922d1 --- /dev/null +++ b/packages/lint-repository-sui/test/TestHelpers.js @@ -0,0 +1,64 @@ +import {expect} from 'chai' +import {stub} from 'sinon' +export class RuleTester { + id + handler + + static create(id, handler) { + return new RuleTester(id, handler) + } + + constructor(id, handler) { + this.handler = handler + this.id = id + } + + run(assertions) { + const instance = this + + Object.entries(assertions).forEach(([kind, tests]) => { + describe(`[${kind.toUpperCase()}] ${this.id}`, function () { + beforeEach(function () { + this.ctxt = { + report: stub(), + monitoring: stub() + } + }) + afterEach(function () { + this.ctxt.report.reset() + this.ctxt.monitoring.reset() + }) + + tests.forEach(assertion => { + const {monitoring, report, name, ...rest} = assertion + Object.entries(rest).forEach(([FSPattern, matches]) => { + it(name ?? FSPattern, function () { + instance.handler.create(this.ctxt)[FSPattern](matches) + monitoring && expect(this.ctxt.monitoring.calledWith(monitoring)).to.be.eql(true) + report && expect(instance._formatMessages(this.ctxt.report)).to.be.eqls(report) + expect(true).to.be.eql(true) + }) + }) + }) + }) + }) + } + + _formatMessages(stub) { + const report = stub.firstCall.firstArg + return Object.entries(report.data ?? {}).reduce((acc, [key, value]) => { + return acc.replaceAll(`{{${key}}}`, value) + }, this.handler.meta.messages[report.messageId]) + } +} + +export class MatchStub { + static create({parsed, raw}) { + return new MatchStub(parsed, raw) + } + + constructor(parsed, raw) { + this.parsed = parsed + this.raw = raw + } +} diff --git a/packages/lint-repository-sui/test/rules/github-actionSpec.js b/packages/lint-repository-sui/test/rules/github-actionSpec.js new file mode 100644 index 000000000..17f4ecb5e --- /dev/null +++ b/packages/lint-repository-sui/test/rules/github-actionSpec.js @@ -0,0 +1,53 @@ +import dedent from 'dedent' + +import handler from '../../src/rules/github-action.js' +import {RuleTester} from '../TestHelpers' + +RuleTester.create('github-action', handler).run({ + valid: [ + { + '.github/workflows': [], + name: 'The porject has define a worflows folder', + monitoring: true + }, + { + '.github/**/main.yml': [], + name: 'The porject has define a worflow for the main branch', + monitoring: true + }, + { + '.github/**/pullrequest.yml': [], + name: 'The porject has define a worflow for PRs', + monitoring: true + } + ], + invalid: [ + { + missmatch: '.github/workflows', + name: 'The porject has NOT define a worflows folder', + report: dedent` + Every project needs to have a .github/worflows folder to be able to run CI/CD in GHA. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: false + }, + { + missmatch: '.github/**/main.yml', + name: 'The porject has NOT define a worflow for the main branch', + report: dedent` + Every project needs to have a workflow to run on master. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: false + }, + { + missmatch: '.github/**/pullrequest.yml', + name: 'The porject has NOT define a worflow for PRs', + report: dedent` + Every project needs to have a workflow to run on every PR. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: false + } + ] +}) diff --git a/packages/lint-repository-sui/test/rules/node-versionSpec.js b/packages/lint-repository-sui/test/rules/node-versionSpec.js new file mode 100644 index 000000000..380bfcbd2 --- /dev/null +++ b/packages/lint-repository-sui/test/rules/node-versionSpec.js @@ -0,0 +1,44 @@ +import dedent from 'dedent' + +import handler from '../../src/rules/node-version.js' +import {MatchStub, RuleTester} from '../TestHelpers' + +RuleTester.create('node-version', handler).run({ + valid: [ + { + '.nvmrc': [MatchStub.create({raw: '20'})], + name: 'nvmrc Exists and has setup the version 20', + monitoring: '20' + } + ], + invalid: [ + { + '.nvmrc': [MatchStub.create({raw: '20'}), MatchStub.create({raw: 17})], + name: 'Exits more than one nvmrc file', + report: dedent` + Your project has more than one .nvmrc file. That can be dangerous. + Please, use onle ONE in the root of your project. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + }, + { + '.nvmrc': [MatchStub.create({raw: '16'})], + name: 'Exits more than one nvmrc file', + report: dedent` + Your current Node version is 16. + Please be sure that your repository use the latest Node Version 20. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + }, + { + missmatch: '', + report: dedent` + Every project have to have a .npmrc file to define the node versión. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + } + ] +}) diff --git a/packages/lint-repository-sui/test/rules/package-lockSpec.js b/packages/lint-repository-sui/test/rules/package-lockSpec.js new file mode 100644 index 000000000..dd3cc21a0 --- /dev/null +++ b/packages/lint-repository-sui/test/rules/package-lockSpec.js @@ -0,0 +1,25 @@ +import dedent from 'dedent' + +import handler from '../../src/rules/package-lock.js' +import {RuleTester} from '../TestHelpers' + +RuleTester.create('package-lock', handler).run({ + valid: [ + { + 'package-lock.json': [], + name: 'Project has package-lock.json in the root folder', + monitoring: true + } + ], + invalid: [ + { + missmatch: '', + name: 'Project doesnt has package-lock in the root folder', + report: dedent` + Every project needs to have a package-lock.json file to be used in CI/CD. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: false + } + ] +}) diff --git a/packages/lint-repository-sui/test/rules/react-versionSpec.js b/packages/lint-repository-sui/test/rules/react-versionSpec.js new file mode 100644 index 000000000..a7a50ca49 --- /dev/null +++ b/packages/lint-repository-sui/test/rules/react-versionSpec.js @@ -0,0 +1,44 @@ +import dedent from 'dedent' + +import handler from '../../src/rules/react-version.js' +import {MatchStub, RuleTester} from '../TestHelpers' + +RuleTester.create('react-version', handler).run({ + valid: [ + { + 'package-lock.json': [MatchStub.create({parsed: {packages: {'node_modules/react': {version: '18.0.0'}}}})], + name: 'React 18 installed', + monitoring: '18' + } + ], + invalid: [ + { + 'package-lock.json': [MatchStub.create({parsed: {packages: {}}})], + name: 'React not installed', + report: dedent` + Your project doesnt have installed React. + Please install at least the version 18. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + }, + { + 'package-lock.json': [MatchStub.create({parsed: {packages: {'node_modules/react': {version: '17.0.0'}}}})], + name: 'React wrong version', + report: dedent` + Please be sure that your repository use the latest React Version 18. + Your current version is 17. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: '17' + }, + { + missmatch: '', + report: dedent` + To calculate the react version first we need to have a package-lock.json in the root + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + } + ] +}) From 3a8a6d58955d7f3d4fce97db4cd03223d079ac81 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Fri, 1 Mar 2024 14:43:16 +0100 Subject: [PATCH 17/47] test(packages/sui-lint): Add firsts tests to the RepositoryLinter --- .../sui-lint/src/RepositoryLinter/Config.js | 12 ++- .../sui-lint/src/RepositoryLinter/Match.js | 22 ++++- .../sui-lint/src/RepositoryLinter/Results.js | 19 ++-- .../sui-lint/src/RepositoryLinter/Runner.js | 12 ++- .../sui-lint/src/RepositoryLinter/index.js | 4 +- .../test/RepositoryLinter/ConfigSpec.js | 38 +++++++ .../test/RepositoryLinter/MatchSpec.js | 99 +++++++++++++++++++ .../test/RepositoryLinter/ResultsSpec.js | 44 +++++++++ .../test/RepositoryLinter/indexSpec.js | 0 9 files changed, 229 insertions(+), 21 deletions(-) create mode 100644 packages/sui-lint/test/RepositoryLinter/ConfigSpec.js create mode 100644 packages/sui-lint/test/RepositoryLinter/MatchSpec.js create mode 100644 packages/sui-lint/test/RepositoryLinter/ResultsSpec.js create mode 100644 packages/sui-lint/test/RepositoryLinter/indexSpec.js diff --git a/packages/sui-lint/src/RepositoryLinter/Config.js b/packages/sui-lint/src/RepositoryLinter/Config.js index 6def2e744..57d09eaf5 100644 --- a/packages/sui-lint/src/RepositoryLinter/Config.js +++ b/packages/sui-lint/src/RepositoryLinter/Config.js @@ -4,10 +4,10 @@ module.exports.Config = class Config { } async load() { - const repositoryConfig = require('../../repository.config.js') + const repositoryConfig = this.requireConfig() const rules = repositoryConfig.plugins.reduce((acc, pkg) => { - const pkgConfig = require(`lint-repository-${pkg}`) + const pkgConfig = this.requirePkg(pkg) const rulesEntries = Object.entries(pkgConfig.rules) .map(([rule, handler]) => { const key = `${pkg}/${rule}` @@ -20,4 +20,12 @@ module.exports.Config = class Config { return rules } + + requireConfig() { + return require('../../repository.config.js') + } + + requirePkg(pkg) { + return require(`lint-repository-${pkg}`) + } } diff --git a/packages/sui-lint/src/RepositoryLinter/Match.js b/packages/sui-lint/src/RepositoryLinter/Match.js index 4dbd19ff5..73c8b6e4a 100644 --- a/packages/sui-lint/src/RepositoryLinter/Match.js +++ b/packages/sui-lint/src/RepositoryLinter/Match.js @@ -2,10 +2,19 @@ const {extname} = require('path') const yaml = require('js-yaml') const fs = require('fs') -module.exports.Match = class Match { +class CustomFileReader { + static create() { return new CustomFileReader() } // eslint-disable-line + + isDirectory(path) { return fs.statSync(process.cwd() + '/' + path).isDirectory() } // eslint-disable-line + parseYML(path) { return yaml.load(fs.readFileSync(process.cwd() + '/' + path, 'utf8')) } // eslint-disable-line + parseJSON(path) { return require(process.cwd() + '/' + path) } // eslint-disable-line + raw(path) { return fs.readFileSync(process.cwd() + '/' + path, 'utf8') } // eslint-disable-line +} + +class Match { static create(path) { const ext = extname(path) - if (!ext && fs.statSync(process.cwd() + '/' + path).isDirectory()) { + if (!ext && CustomFileReader.create().isDirectory(path)) { return new Match(path, undefined, undefined, true) } @@ -13,14 +22,14 @@ module.exports.Match = class Match { let raw switch (ext) { case '.json': - parsed = require(process.cwd() + '/' + path) + parsed = CustomFileReader.create().parseJSON(path) break case '.yml': case '.yaml': - parsed = yaml.load(fs.readFileSync(process.cwd() + '/' + path, 'utf8')) + parsed = CustomFileReader.create().parseYML(path) break default: - raw = fs.readFileSync(process.cwd() + '/' + path, 'utf8') + raw = CustomFileReader.create().raw(path) } return new Match(path, parsed, raw, false) @@ -34,3 +43,6 @@ module.exports.Match = class Match { this.fullPath = process.cwd() + '/' + path } } + +module.exports.CustomFileReader = CustomFileReader +module.exports.Match = Match diff --git a/packages/sui-lint/src/RepositoryLinter/Results.js b/packages/sui-lint/src/RepositoryLinter/Results.js index 079ff3ba6..6b837ca75 100644 --- a/packages/sui-lint/src/RepositoryLinter/Results.js +++ b/packages/sui-lint/src/RepositoryLinter/Results.js @@ -8,6 +8,12 @@ module.exports.Results = class Results { #messages #monitorings + static HAPPY_MESSAGE = dedent` + 🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳 + 🥳 Your repository follow all our internal conventions 🥳 + 🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳 + ` + static create(executions) { return new Results(executions) } @@ -22,13 +28,10 @@ module.exports.Results = class Results { return this.#monitorings } + log(msg) { console.log(msg) } // eslint-disable-line + logTable() { - if (this.#messages.length === 0) - return console.log(dedent` - 🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳 - 🥳 Your repository follow all our internal conventions 🥳 - 🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳 - `) + if (this.#messages.length === 0) return this.log(Results.HAPPY_MESSAGE) const p = new Table({ title: dedent` @@ -42,12 +45,12 @@ module.exports.Results = class Results { } logJSON() { - return console.log(JSON.stringify(this.#messages, null, 2)) + return this.log(JSON.stringify(this.#messages, null, 2)) } logMonitorings() { if (this.#monitorings.length === 0) - return console.log(dedent` + return this.log(dedent` There is not signal to be send to DD. Use 'context.monitoring' to add signals at your execution diff --git a/packages/sui-lint/src/RepositoryLinter/Runner.js b/packages/sui-lint/src/RepositoryLinter/Runner.js index 056d3204f..8c3ffc81f 100644 --- a/packages/sui-lint/src/RepositoryLinter/Runner.js +++ b/packages/sui-lint/src/RepositoryLinter/Runner.js @@ -1,13 +1,17 @@ const {Match} = require('./Match') -const fg = require('fast-glob') +const fastGlob = require('fast-glob') module.exports.Runner = class Runner { - static create() { - return new Runner() + static create(fg) { + return new Runner(fg ?? fastGlob) + } + + constructor(fg) { + this.fg = fg } assertion(key) { - const files = fg.sync(key, {ignore: ['node_modules'], onlyFiles: false}) ?? [] + const files = this.fg.sync(key, {ignore: ['node_modules'], onlyFiles: false}) ?? [] return files.map(Match.create) } } diff --git a/packages/sui-lint/src/RepositoryLinter/index.js b/packages/sui-lint/src/RepositoryLinter/index.js index 0399abc92..0178a72d3 100644 --- a/packages/sui-lint/src/RepositoryLinter/index.js +++ b/packages/sui-lint/src/RepositoryLinter/index.js @@ -5,8 +5,8 @@ const {Results} = require('./Results') module.exports.RepositoryLinter = class RepositoryLinter { #cofig - static create() { - return new RepositoryLinter(Config.create()) + static create(config) { + return new RepositoryLinter(config ?? Config.create()) } constructor(config) { diff --git a/packages/sui-lint/test/RepositoryLinter/ConfigSpec.js b/packages/sui-lint/test/RepositoryLinter/ConfigSpec.js new file mode 100644 index 000000000..2960d8d0a --- /dev/null +++ b/packages/sui-lint/test/RepositoryLinter/ConfigSpec.js @@ -0,0 +1,38 @@ +import {expect} from 'chai' +import {stub} from 'sinon' + +import {Config} from '../../src/RepositoryLinter/Config.js' + +describe('Config', function () { + beforeEach(function () { + this.requireConfigStub = stub(Config.prototype, 'requireConfig') + this.requirePkgStub = stub(Config.prototype, 'requirePkg') + }) + + afterEach(function () { + this.requireConfigStub.reset() + this.requirePkgStub.reset() + }) + + it('Should return a rules object', async function () { + // Given + const handler = { + meta: {messages: {badVersion: 'Your react version is not 20'}}, + create: function () {} + } + this.requireConfigStub.returns({ + plugins: ['tester'], + rules: { + 'tester/react-version': 1 + } + }) + this.requirePkgStub.returns({rules: {'react-version': handler}}) + + // When + const rulesLoaded = await Config.create().load() + + // Then + expect(this.requirePkgStub.calledWith('tester')).to.be.eql(true) + expect(rulesLoaded).to.be.eqls({'tester/react-version': {handler, level: 1}}) + }) +}) diff --git a/packages/sui-lint/test/RepositoryLinter/MatchSpec.js b/packages/sui-lint/test/RepositoryLinter/MatchSpec.js new file mode 100644 index 000000000..5db0c60c7 --- /dev/null +++ b/packages/sui-lint/test/RepositoryLinter/MatchSpec.js @@ -0,0 +1,99 @@ +import {expect} from 'chai' +import {stub} from 'sinon' + +import {CustomFileReader, Match} from '../../src/RepositoryLinter/Match.js' + +describe('Match', function () { + beforeEach(function () { + this.isDirStub = stub(CustomFileReader.prototype, 'isDirectory') + + this.parseYMLStub = stub(CustomFileReader.prototype, 'parseYML') + this.parseJSONStub = stub(CustomFileReader.prototype, 'parseJSON') + this.rawStub = stub(CustomFileReader.prototype, 'raw') + }) + + afterEach(function () { + this.isDirStub.restore() + + this.parseYMLStub.restore() + this.parseJSONStub.restore() + this.rawStub.restore() + }) + + it('Should detect directories', function () { + // Given + this.isDirStub.returns(true) + + // When + const match = Match.create('/dir/path') + + // Then + expect(match.isDir).to.be.eqls(true) + }) + + it('Should detect files w/out extensions', function () { + // Given + this.isDirStub.returns(false) + this.rawStub.returns('20') + + // When + const match = Match.create('/dir/path') + + // Then + expect(match.isDir).to.be.eqls(false) + expect(this.rawStub.calledWith('/dir/path')).to.be.eql(true) + }) + + it('Should parse JSON files', function () { + // Given + this.isDirStub.returns(false) + this.parseJSONStub.returns({a: 1}) + + // When + const match = Match.create('/dir/file.json') + + // Then + expect(match.parsed).to.be.eqls({a: 1}) + expect(this.parseJSONStub.calledWith('/dir/file.json')).to.be.eql(true) + }) + + it('Should parse yml files', function () { + // Given + this.isDirStub.returns(false) + this.parseYMLStub.returns({a: 1}) + + // When + const match = Match.create('/dir/file.yml') + + // Then + expect(match.parsed).to.be.eqls({a: 1}) + expect(this.parseYMLStub.calledWith('/dir/file.yml')).to.be.eql(true) + }) + + it('Should parse yaml files', function () { + // Given + this.isDirStub.returns(false) + this.parseYMLStub.returns({a: 1}) + + // When + const match = Match.create('/dir/file.yaml') + + // Then + expect(match.parsed).to.be.eqls({a: 1}) + expect(this.parseYMLStub.calledWith('/dir/file.yaml')).to.be.eql(true) + }) + + it('Should read unkown files', function () { + // Given + this.isDirStub.returns(false) + this.rawStub.returns('Hello') + + // When + const match = Match.create('/dir/file.txt') + + // Then + expect(match.raw).to.be.eqls('Hello') + expect(match.parsed).to.be.eqls(undefined) + expect(this.rawStub.calledWith('/dir/file.txt')).to.be.eql(true) + }) +}) diff --git a/packages/sui-lint/test/RepositoryLinter/ResultsSpec.js b/packages/sui-lint/test/RepositoryLinter/ResultsSpec.js new file mode 100644 index 000000000..311911f23 --- /dev/null +++ b/packages/sui-lint/test/RepositoryLinter/ResultsSpec.js @@ -0,0 +1,44 @@ +import {expect} from 'chai' +import {Table} from 'console-table-printer' +import {stub} from 'sinon' + +import {Results} from '../../src/RepositoryLinter/Results.js' + +describe('Results', function () { + beforeEach(function () { + this.addRowStub = stub(Table.prototype, 'addRow') + this.printTableStub = stub(Table.prototype, 'printTable') + + this.logStub = stub(Results.prototype, 'log') + }) + + afterEach(function () { + this.addRowStub.restore() + this.printTableStub.restore() + + this.logStub.restore() + }) + + it('Should print Happy Message it there is not messages', function () { + const executions = [ + { + messages: [], + signal: false + } + ] + Results.create(executions).logTable() + + expect(this.logStub.calledWith(Results.HAPPY_MESSAGE)).to.be.eq(true) + }) + + it('Should print a table with all the messages', function () { + const executions = [ + {messages: [{rule: 'tester/node-version', message: 'Node version fail', level: 1}], signal: 12}, + {messages: [{rule: 'tester/react-version', message: 'React version fail', level: 2}], signal: 17}, + {messages: [], signal: true} + ] + Results.create(executions).logTable() + + // expect(this.logStub.calledWith(Results.HAPPY_MESSAGE)).to.be.eq(true) + }) +}) diff --git a/packages/sui-lint/test/RepositoryLinter/indexSpec.js b/packages/sui-lint/test/RepositoryLinter/indexSpec.js new file mode 100644 index 000000000..e69de29bb From 0727399c1a348b3e2d16a0973a82953701683403 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 14:45:04 +0100 Subject: [PATCH 18/47] test(packages/sui-lint): Add more unit test for the RepositoryLinter package --- .../sui-lint/src/RepositoryLinter/Context.js | 15 +- .../sui-lint/src/RepositoryLinter/Match.js | 4 + .../test/RepositoryLinter/ContextSpec.js | 206 ++++++++++++++++++ .../test/RepositoryLinter/ResultsSpec.js | 41 +++- .../test/RepositoryLinter/RunnerSpec.js | 26 +++ .../test/RepositoryLinter/indexSpec.js | 0 6 files changed, 284 insertions(+), 8 deletions(-) create mode 100644 packages/sui-lint/test/RepositoryLinter/ContextSpec.js create mode 100644 packages/sui-lint/test/RepositoryLinter/RunnerSpec.js delete mode 100644 packages/sui-lint/test/RepositoryLinter/indexSpec.js diff --git a/packages/sui-lint/src/RepositoryLinter/Context.js b/packages/sui-lint/src/RepositoryLinter/Context.js index 72ceebb04..e04f769f6 100644 --- a/packages/sui-lint/src/RepositoryLinter/Context.js +++ b/packages/sui-lint/src/RepositoryLinter/Context.js @@ -8,8 +8,13 @@ module.exports.Context = class Context { #handler #runner - static create(level, handler, rule) { - return new Context(level, handler, rule, Runner.create()) + static MISSING_REDUCER_MONITORING_MSG = ` + [RepositoryLinter Context#signal] If your has call to 'context.monitoring' more than one time in your rule. + You have to create a function 'reduceMonitoring' to be able reduce all of them to 1 value. + ` + + static create(level, handler, rule, runner) { + return new Context(level, handler, rule, runner ?? Runner.create()) } constructor(level, handler, rule, runner) { @@ -49,11 +54,7 @@ module.exports.Context = class Context { if (this.#monitorings.length === 0) return _signal if (this.#monitorings.length === 1) return {..._signal, value: this.#monitorings[0].value} - if (this.#handler.reduceMonitoring === undefined) - throw new Error(` - [RepositoryLinter Context#signal] If your has call to 'context.monitoring' more than one time in your rule. - You have to create a function 'reduceMonitoring' to be able reduce all of them to 1 value. - `) + if (this.#handler.reduceMonitoring === undefined) throw new Error(Context.MISSING_REDUCER_MONITORING_MSG) return {rule: this.rule, level: this.level, value: this.#handler?.reduceMonitoring(this.#monitorings)} } diff --git a/packages/sui-lint/src/RepositoryLinter/Match.js b/packages/sui-lint/src/RepositoryLinter/Match.js index 73c8b6e4a..ffb826b85 100644 --- a/packages/sui-lint/src/RepositoryLinter/Match.js +++ b/packages/sui-lint/src/RepositoryLinter/Match.js @@ -12,6 +12,10 @@ class CustomFileReader { } class Match { + static empty() { + return new Match(undefined, undefined, undefined, false) + } + static create(path) { const ext = extname(path) if (!ext && CustomFileReader.create().isDirectory(path)) { diff --git a/packages/sui-lint/test/RepositoryLinter/ContextSpec.js b/packages/sui-lint/test/RepositoryLinter/ContextSpec.js new file mode 100644 index 000000000..fd640bcd4 --- /dev/null +++ b/packages/sui-lint/test/RepositoryLinter/ContextSpec.js @@ -0,0 +1,206 @@ +import {expect} from 'chai' +import {spy, stub} from 'sinon' + +import {Context} from '../../src/RepositoryLinter/Context.js' +import {Match} from '../../src/RepositoryLinter/Match.js' + +const LEVELS = { + OFF: 0, + WARNING: 1, + ERROR: 2 +} + +describe('Context', function () { + beforeEach(function () { + this.reportSpy = spy(Context.prototype, 'report') + this.monitoringSpy = spy(Context.prototype, 'monitoring') + this.runnerStub = {assertion: stub()} + this.handlerStub = { + meta: {messages: {badVersion: 'Message for your bad version'}}, + __assertionStub: stub(), + __missmatchStub: stub(), + create() { + return { + 'package.json': this.__assertionStub, + missmatch: this.__missmatchStub + } + } + } + + this.handlerInnerStub = { + meta: {messages: {badVersion: 'Message for your bad version', badKey: 'Message for bad {{key}}'}}, + create(context) { + return { + 'package.json': matches => { + context.report({messageId: 'badVersion'}) + context.monitoring(true) + }, + missmatch: key => { + context.report({messageId: 'badKey', data: {key}}) + context.monitoring(false) + } + } + } + } + + this.handlerReducerMonitoringStub = { + meta: {messages: {badVersion: 'Message for your bad version', badKey: 'Message for bad {{key}}'}}, + reduceMonitoring: stub(), + create(context) { + return { + 'package.json': matches => { + context.monitoring(true) + context.monitoring(false) + } + } + } + } + }) + + afterEach(function () { + this.handlerStub.__assertionStub.reset() + this.handlerStub.__missmatchStub.reset() + + this.monitoringSpy.restore() + this.reportSpy.restore() + + this.runnerStub.assertion.reset() + + this.handlerReducerMonitoringStub.reduceMonitoring?.reset() + }) + + it('Should call to the assertions in the handler when there is Match', function () { + // Given + const emptyMatch = Match.empty() + this.runnerStub.assertion.returns([emptyMatch]) + + // When + Context.create(LEVELS.WARNING, this.handlerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(this.handlerStub.__assertionStub.firstCall.firstArg).to.be.instanceof(Array) + expect(this.handlerStub.__assertionStub.firstCall.firstArg[0]).to.be.eql(emptyMatch) + }) + + it('Should call to the missmatch in the handler when there is not Match with the "failing" key', function () { + // Given + this.runnerStub.assertion.returns([]) + + // When + Context.create(LEVELS.WARNING, this.handlerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(this.handlerStub.__assertionStub.firstCall).to.be.eql(null) + expect(this.handlerStub.__missmatchStub.firstCall.firstArg).to.be.eql('package.json') + }) + + it('Should create new monitorings and messages from assertion function', function () { + // Given + this.runnerStub.assertion.returns([Match.empty()]) + + // When + Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(this.reportSpy.firstCall.firstArg).to.be.eql({messageId: 'badVersion'}) + expect(this.monitoringSpy.firstCall.firstArg).to.be.eql(true) + }) + + it('Should create new monitorings and messages from missmatch function', function () { + // Given + this.runnerStub.assertion.returns([]) + + // When + Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(this.reportSpy.firstCall.firstArg).to.be.eql({messageId: 'badKey', data: {key: 'package.json'}}) + expect(this.monitoringSpy.firstCall.firstArg).to.be.eql(false) + }) + + it('Should properly format the messages', function () { + // Given + this.runnerStub.assertion.returns([]) + + // When + const context = Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(context.messages).to.be.eql([ + { + rule: 'tests/node-version', + message: 'Message for bad package.json', + level: 1, + messageId: 'badKey', + data: {key: 'package.json'} + } + ]) + }) + + it('Should properly format the monitoring', function () { + // Given + this.runnerStub.assertion.returns([Match.empty()]) + + // When + const context = Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(context.signal).to.be.eql({ + rule: 'tests/node-version', + value: true, + level: 1 + }) + }) + + it('Should require a reduceMonitoring function when there are more than one monitor', function () { + // Given + this.runnerStub.assertion.returns([Match.empty()]) + this.handlerReducerMonitoringStub.reduceMonitoring.returns(false) + + // When + const context = Context.create( + LEVELS.WARNING, + this.handlerReducerMonitoringStub, + 'tests/node-version', + this.runnerStub + ).run() + + // Then + expect(context.signal).to.be.eql({ + rule: 'tests/node-version', + value: false, + level: 1 + }) + expect(this.handlerReducerMonitoringStub.reduceMonitoring.firstCall.firstArg).to.be.eql([ + { + assertion: 'package.json', + rule: 'tests/node-version', + value: true, + level: 1 + }, + { + assertion: 'package.json', + rule: 'tests/node-version', + value: false, + level: 1 + } + ]) + }) + + it('Should throw an exception if the reduceMonitoring function is undefined', function () { + // Given + this.runnerStub.assertion.returns([Match.empty()]) + delete this.handlerReducerMonitoringStub.reduceMonitoring + + // When + const context = Context.create( + LEVELS.WARNING, + this.handlerReducerMonitoringStub, + 'tests/node-version', + this.runnerStub + ).run() + + // Then + expect(() => context.signal).to.be.throw(Context.MISSING_REDUCER_MONITORING_MSG) + }) +}) diff --git a/packages/sui-lint/test/RepositoryLinter/ResultsSpec.js b/packages/sui-lint/test/RepositoryLinter/ResultsSpec.js index 311911f23..ad9cc62c5 100644 --- a/packages/sui-lint/test/RepositoryLinter/ResultsSpec.js +++ b/packages/sui-lint/test/RepositoryLinter/ResultsSpec.js @@ -39,6 +39,45 @@ describe('Results', function () { ] Results.create(executions).logTable() - // expect(this.logStub.calledWith(Results.HAPPY_MESSAGE)).to.be.eq(true) + expect(this.addRowStub.firstCall.firstArg).to.be.eql({rule: 'tester/node-version', message: 'Node version fail'}) + expect(this.addRowStub.firstCall.lastArg).to.be.eql({color: 'yellow'}) + + expect(this.addRowStub.secondCall.firstArg).to.be.eql({rule: 'tester/react-version', message: 'React version fail'}) + expect(this.addRowStub.secondCall.lastArg).to.be.eql({color: 'red'}) + }) + + it('Should print a table with all the monitorings', function () { + const executions = [ + {messages: [{rule: 'tester/node-version', message: 'Node version fail', level: 1}], signal: 12}, + {messages: [{rule: 'tester/react-version', message: 'React version fail', level: 2}], signal: 17}, + {messages: [], signal: true} + ] + Results.create(executions).logMonitorings() + + expect(this.addRowStub.firstCall.firstArg).to.be.eql(12) + expect(this.addRowStub.secondCall.firstArg).to.be.eql(17) + expect(this.addRowStub.thirdCall.firstArg).to.be.eql(true) + }) + + it('Should print a JSON output', function () { + const executions = [ + {messages: [{rule: 'tester/node-version', message: 'Node version fail', level: 1}], signal: 12}, + {messages: [{rule: 'tester/react-version', message: 'React version fail', level: 2}], signal: 17}, + {messages: [], signal: true} + ] + Results.create(executions).logJSON() + + expect( + this.logStub.calledWith( + JSON.stringify( + [ + {rule: 'tester/node-version', message: 'Node version fail', level: 1}, + {rule: 'tester/react-version', message: 'React version fail', level: 2} + ], + null, + 2 + ) + ) + ).to.be.eq(true) }) }) diff --git a/packages/sui-lint/test/RepositoryLinter/RunnerSpec.js b/packages/sui-lint/test/RepositoryLinter/RunnerSpec.js new file mode 100644 index 000000000..5d69d1e58 --- /dev/null +++ b/packages/sui-lint/test/RepositoryLinter/RunnerSpec.js @@ -0,0 +1,26 @@ +import {expect} from 'chai' +import {stub} from 'sinon' + +import {Match} from '../../src/RepositoryLinter/Match' +import {Runner} from '../../src/RepositoryLinter/Runner.js' + +describe('Runner', function () { + beforeEach(function () { + this.syncStub = stub() + this.matchCreateStub = stub(Match, 'create') + }) + + afterEach(function () { + this.syncStub.reset() + this.matchCreateStub.restore() + }) + + it('Should return a list of matches', function () { + this.syncStub.returns(['path/file.json']) + + Runner.create({sync: this.syncStub}).assertion('**/*.json') + + expect(this.matchCreateStub.firstCall.firstArg).to.be.eql('path/file.json') + expect(this.syncStub.firstCall.firstArg).to.be.eql('**/*.json') + }) +}) diff --git a/packages/sui-lint/test/RepositoryLinter/indexSpec.js b/packages/sui-lint/test/RepositoryLinter/indexSpec.js deleted file mode 100644 index e69de29bb..000000000 From 1fa5d6730d9714e52cfb57a97d883f45ab15083c Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 17:20:23 +0100 Subject: [PATCH 19/47] test(packages/eslint-plugin-sui): move to test/server folder --- .../test/server/rules/factory-pattern.js | 41 ++++++++ .../server/rules/serialize-deserialize.js | 96 +++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 packages/eslint-plugin-sui/test/server/rules/factory-pattern.js create mode 100644 packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js diff --git a/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js b/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js new file mode 100644 index 000000000..9f961d232 --- /dev/null +++ b/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js @@ -0,0 +1,41 @@ +import dedent from 'dedent' +import {RuleTester} from 'eslint' + +import rule from '../../../src/rules/factory-pattern' + +// ------------------------------------------------------------------------------ +// Tests +// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) +ruleTester.run('factory-pattern', rule, { + valid: [ + { + code: dedent` + class User { + static create() { return new User() } + } + ` + } + ], + + invalid: [ + { + code: dedent` + class Model { + constructor() { this.name = 'John Doe' } + }`, + errors: [ + { + message: dedent` + You have to define at least one static function that return an instance of your class. + Avoid to use the 'new' keyword directly in your code. + Use always a factory function + `, + type: 'ClassDeclaration' + } + ] + } + ] +}) diff --git a/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js new file mode 100644 index 000000000..b9d952b68 --- /dev/null +++ b/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js @@ -0,0 +1,96 @@ +import dedent from 'dedent' +import {RuleTester} from 'eslint' + +import rule from '../../../src/rules/serialize-deserialize' + +// ------------------------------------------------------------------------------ +// Tests +// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) +ruleTester.run('serialize-deserialize', rule, { + valid: [ + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + id: this.id, + name: this.name + } + } + } + ` + } + ], + + invalid: [ + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return this.id + } + } + `, + errors: [ + { + message: dedent`toJSON should return an object` + } + ] + }, + { + code: dedent` + class User { + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + Noid: this.id, + Noname: this.name + } + } + } + `, + errors: [ + { + message: dedent` + If your class has a 'toJSON' method. You have to define a 'static create' method too. + The output of the 'toJSON' should be the same as the input of your 'static create' method + ` + } + ] + }, + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + Noid: this.id, + Noname: this.name + } + } + } + `, + errors: [{message: 'Missing toJSON properties (id, name)'}] + } + ] +}) From 503b1bd7d080944995efa192a241f063c1e53cfa Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 17:31:43 +0100 Subject: [PATCH 20/47] test(packages/lint-repository-sui): move tests to server --- .../test/{ => server}/rules/github-actionSpec.js | 2 +- .../test/{ => server}/rules/node-versionSpec.js | 2 +- .../test/{ => server}/rules/package-lockSpec.js | 2 +- .../test/{ => server}/rules/react-versionSpec.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename packages/lint-repository-sui/test/{ => server}/rules/github-actionSpec.js (96%) rename packages/lint-repository-sui/test/{ => server}/rules/node-versionSpec.js (95%) rename packages/lint-repository-sui/test/{ => server}/rules/package-lockSpec.js (92%) rename packages/lint-repository-sui/test/{ => server}/rules/react-versionSpec.js (95%) diff --git a/packages/lint-repository-sui/test/rules/github-actionSpec.js b/packages/lint-repository-sui/test/server/rules/github-actionSpec.js similarity index 96% rename from packages/lint-repository-sui/test/rules/github-actionSpec.js rename to packages/lint-repository-sui/test/server/rules/github-actionSpec.js index 17f4ecb5e..9f78fd091 100644 --- a/packages/lint-repository-sui/test/rules/github-actionSpec.js +++ b/packages/lint-repository-sui/test/server/rules/github-actionSpec.js @@ -1,7 +1,7 @@ import dedent from 'dedent' import handler from '../../src/rules/github-action.js' -import {RuleTester} from '../TestHelpers' +import {RuleTester} from '../../TestHelpers.js' RuleTester.create('github-action', handler).run({ valid: [ diff --git a/packages/lint-repository-sui/test/rules/node-versionSpec.js b/packages/lint-repository-sui/test/server/rules/node-versionSpec.js similarity index 95% rename from packages/lint-repository-sui/test/rules/node-versionSpec.js rename to packages/lint-repository-sui/test/server/rules/node-versionSpec.js index 380bfcbd2..31a46d51a 100644 --- a/packages/lint-repository-sui/test/rules/node-versionSpec.js +++ b/packages/lint-repository-sui/test/server/rules/node-versionSpec.js @@ -1,7 +1,7 @@ import dedent from 'dedent' import handler from '../../src/rules/node-version.js' -import {MatchStub, RuleTester} from '../TestHelpers' +import {MatchStub, RuleTester} from '../../TestHelpers.js' RuleTester.create('node-version', handler).run({ valid: [ diff --git a/packages/lint-repository-sui/test/rules/package-lockSpec.js b/packages/lint-repository-sui/test/server/rules/package-lockSpec.js similarity index 92% rename from packages/lint-repository-sui/test/rules/package-lockSpec.js rename to packages/lint-repository-sui/test/server/rules/package-lockSpec.js index dd3cc21a0..533ccafe7 100644 --- a/packages/lint-repository-sui/test/rules/package-lockSpec.js +++ b/packages/lint-repository-sui/test/server/rules/package-lockSpec.js @@ -1,7 +1,7 @@ import dedent from 'dedent' import handler from '../../src/rules/package-lock.js' -import {RuleTester} from '../TestHelpers' +import {RuleTester} from '../../TestHelpers.js' RuleTester.create('package-lock', handler).run({ valid: [ diff --git a/packages/lint-repository-sui/test/rules/react-versionSpec.js b/packages/lint-repository-sui/test/server/rules/react-versionSpec.js similarity index 95% rename from packages/lint-repository-sui/test/rules/react-versionSpec.js rename to packages/lint-repository-sui/test/server/rules/react-versionSpec.js index a7a50ca49..f890d9a39 100644 --- a/packages/lint-repository-sui/test/rules/react-versionSpec.js +++ b/packages/lint-repository-sui/test/server/rules/react-versionSpec.js @@ -1,7 +1,7 @@ import dedent from 'dedent' import handler from '../../src/rules/react-version.js' -import {MatchStub, RuleTester} from '../TestHelpers' +import {MatchStub, RuleTester} from '../../TestHelpers.js' RuleTester.create('react-version', handler).run({ valid: [ From 29e81668de6b8e6b80782201f5a46ebf25b6fdb6 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 17:32:34 +0100 Subject: [PATCH 21/47] test(packages/sui-lint): move to server folder --- .../sui-lint/test/{ => server}/RepositoryLinter/ConfigSpec.js | 0 .../sui-lint/test/{ => server}/RepositoryLinter/ContextSpec.js | 0 packages/sui-lint/test/{ => server}/RepositoryLinter/MatchSpec.js | 0 .../sui-lint/test/{ => server}/RepositoryLinter/ResultsSpec.js | 0 .../sui-lint/test/{ => server}/RepositoryLinter/RunnerSpec.js | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename packages/sui-lint/test/{ => server}/RepositoryLinter/ConfigSpec.js (100%) rename packages/sui-lint/test/{ => server}/RepositoryLinter/ContextSpec.js (100%) rename packages/sui-lint/test/{ => server}/RepositoryLinter/MatchSpec.js (100%) rename packages/sui-lint/test/{ => server}/RepositoryLinter/ResultsSpec.js (100%) rename packages/sui-lint/test/{ => server}/RepositoryLinter/RunnerSpec.js (100%) diff --git a/packages/sui-lint/test/RepositoryLinter/ConfigSpec.js b/packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js similarity index 100% rename from packages/sui-lint/test/RepositoryLinter/ConfigSpec.js rename to packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js diff --git a/packages/sui-lint/test/RepositoryLinter/ContextSpec.js b/packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js similarity index 100% rename from packages/sui-lint/test/RepositoryLinter/ContextSpec.js rename to packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js diff --git a/packages/sui-lint/test/RepositoryLinter/MatchSpec.js b/packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js similarity index 100% rename from packages/sui-lint/test/RepositoryLinter/MatchSpec.js rename to packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js diff --git a/packages/sui-lint/test/RepositoryLinter/ResultsSpec.js b/packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js similarity index 100% rename from packages/sui-lint/test/RepositoryLinter/ResultsSpec.js rename to packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js diff --git a/packages/sui-lint/test/RepositoryLinter/RunnerSpec.js b/packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js similarity index 100% rename from packages/sui-lint/test/RepositoryLinter/RunnerSpec.js rename to packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js From 424b443d9d2d9ce6f3a1fa55b089dc7d23a95734 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 17:33:43 +0100 Subject: [PATCH 22/47] test(packages/eslint-plugin-sui): remove tests folder --- .../tests/src/rules/factory-pattern.js | 41 -------- .../tests/src/rules/serialize-deserialize.js | 96 ------------------- 2 files changed, 137 deletions(-) delete mode 100644 packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js delete mode 100644 packages/eslint-plugin-sui/tests/src/rules/serialize-deserialize.js diff --git a/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js b/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js deleted file mode 100644 index 9f961d232..000000000 --- a/packages/eslint-plugin-sui/tests/src/rules/factory-pattern.js +++ /dev/null @@ -1,41 +0,0 @@ -import dedent from 'dedent' -import {RuleTester} from 'eslint' - -import rule from '../../../src/rules/factory-pattern' - -// ------------------------------------------------------------------------------ -// Tests -// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester -// ------------------------------------------------------------------------------ - -const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) -ruleTester.run('factory-pattern', rule, { - valid: [ - { - code: dedent` - class User { - static create() { return new User() } - } - ` - } - ], - - invalid: [ - { - code: dedent` - class Model { - constructor() { this.name = 'John Doe' } - }`, - errors: [ - { - message: dedent` - You have to define at least one static function that return an instance of your class. - Avoid to use the 'new' keyword directly in your code. - Use always a factory function - `, - type: 'ClassDeclaration' - } - ] - } - ] -}) diff --git a/packages/eslint-plugin-sui/tests/src/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/tests/src/rules/serialize-deserialize.js deleted file mode 100644 index b9d952b68..000000000 --- a/packages/eslint-plugin-sui/tests/src/rules/serialize-deserialize.js +++ /dev/null @@ -1,96 +0,0 @@ -import dedent from 'dedent' -import {RuleTester} from 'eslint' - -import rule from '../../../src/rules/serialize-deserialize' - -// ------------------------------------------------------------------------------ -// Tests -// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester -// ------------------------------------------------------------------------------ - -const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) -ruleTester.run('serialize-deserialize', rule, { - valid: [ - { - code: dedent` - class User { - static create({id, name}) { return new User(id, name) } - constructor(id, name) { - this.id = id - this.name = name - } - toJSON() { - return { - id: this.id, - name: this.name - } - } - } - ` - } - ], - - invalid: [ - { - code: dedent` - class User { - static create({id, name}) { return new User(id, name) } - constructor(id, name) { - this.id = id - this.name = name - } - toJSON() { - return this.id - } - } - `, - errors: [ - { - message: dedent`toJSON should return an object` - } - ] - }, - { - code: dedent` - class User { - constructor(id, name) { - this.id = id - this.name = name - } - toJSON() { - return { - Noid: this.id, - Noname: this.name - } - } - } - `, - errors: [ - { - message: dedent` - If your class has a 'toJSON' method. You have to define a 'static create' method too. - The output of the 'toJSON' should be the same as the input of your 'static create' method - ` - } - ] - }, - { - code: dedent` - class User { - static create({id, name}) { return new User(id, name) } - constructor(id, name) { - this.id = id - this.name = name - } - toJSON() { - return { - Noid: this.id, - Noname: this.name - } - } - } - `, - errors: [{message: 'Missing toJSON properties (id, name)'}] - } - ] -}) From 69c7d64af536cddca4a783febd308a55fd94f4ba Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 17:53:24 +0100 Subject: [PATCH 23/47] test(packages/eslint-plugin-sui): fix import path --- packages/eslint-plugin-sui/test/server/rules/factory-pattern.js | 2 +- .../test/server/rules/serialize-deserialize.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js b/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js index 9f961d232..458134e3d 100644 --- a/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js +++ b/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js @@ -1,7 +1,7 @@ import dedent from 'dedent' import {RuleTester} from 'eslint' -import rule from '../../../src/rules/factory-pattern' +import rule from '../../../src/rules/factory-pattern.js' // ------------------------------------------------------------------------------ // Tests diff --git a/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js index b9d952b68..e42234289 100644 --- a/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js +++ b/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js @@ -1,7 +1,7 @@ import dedent from 'dedent' import {RuleTester} from 'eslint' -import rule from '../../../src/rules/serialize-deserialize' +import rule from '../../../src/rules/serialize-deserialize.js' // ------------------------------------------------------------------------------ // Tests From 6ea3cd7edd2f2dc713f90dd65c5eeacb867831c3 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 17:53:58 +0100 Subject: [PATCH 24/47] test(packages/lint-repository-sui): fix path import --- .../lint-repository-sui/test/server/rules/github-actionSpec.js | 2 +- .../lint-repository-sui/test/server/rules/node-versionSpec.js | 2 +- .../lint-repository-sui/test/server/rules/package-lockSpec.js | 2 +- .../lint-repository-sui/test/server/rules/react-versionSpec.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/lint-repository-sui/test/server/rules/github-actionSpec.js b/packages/lint-repository-sui/test/server/rules/github-actionSpec.js index 9f78fd091..67f21665a 100644 --- a/packages/lint-repository-sui/test/server/rules/github-actionSpec.js +++ b/packages/lint-repository-sui/test/server/rules/github-actionSpec.js @@ -1,6 +1,6 @@ import dedent from 'dedent' -import handler from '../../src/rules/github-action.js' +import handler from '../../../src/rules/github-action.js' import {RuleTester} from '../../TestHelpers.js' RuleTester.create('github-action', handler).run({ diff --git a/packages/lint-repository-sui/test/server/rules/node-versionSpec.js b/packages/lint-repository-sui/test/server/rules/node-versionSpec.js index 31a46d51a..242ee636d 100644 --- a/packages/lint-repository-sui/test/server/rules/node-versionSpec.js +++ b/packages/lint-repository-sui/test/server/rules/node-versionSpec.js @@ -1,6 +1,6 @@ import dedent from 'dedent' -import handler from '../../src/rules/node-version.js' +import handler from '../../../src/rules/node-version.js' import {MatchStub, RuleTester} from '../../TestHelpers.js' RuleTester.create('node-version', handler).run({ diff --git a/packages/lint-repository-sui/test/server/rules/package-lockSpec.js b/packages/lint-repository-sui/test/server/rules/package-lockSpec.js index 533ccafe7..6684cfc4e 100644 --- a/packages/lint-repository-sui/test/server/rules/package-lockSpec.js +++ b/packages/lint-repository-sui/test/server/rules/package-lockSpec.js @@ -1,6 +1,6 @@ import dedent from 'dedent' -import handler from '../../src/rules/package-lock.js' +import handler from '../../../src/rules/package-lock.js' import {RuleTester} from '../../TestHelpers.js' RuleTester.create('package-lock', handler).run({ diff --git a/packages/lint-repository-sui/test/server/rules/react-versionSpec.js b/packages/lint-repository-sui/test/server/rules/react-versionSpec.js index f890d9a39..abb63b6ca 100644 --- a/packages/lint-repository-sui/test/server/rules/react-versionSpec.js +++ b/packages/lint-repository-sui/test/server/rules/react-versionSpec.js @@ -1,6 +1,6 @@ import dedent from 'dedent' -import handler from '../../src/rules/react-version.js' +import handler from '../../../src/rules/react-version.js' import {MatchStub, RuleTester} from '../../TestHelpers.js' RuleTester.create('react-version', handler).run({ From b01ae7ea6f5f3648f94ec6a73f6de42b063a50ec Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 17:54:34 +0100 Subject: [PATCH 25/47] test(packages/sui-lint): fix import path --- packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js | 2 +- packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js | 4 ++-- packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js | 2 +- packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js | 2 +- packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js b/packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js index 2960d8d0a..0261735b2 100644 --- a/packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js +++ b/packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js @@ -1,7 +1,7 @@ import {expect} from 'chai' import {stub} from 'sinon' -import {Config} from '../../src/RepositoryLinter/Config.js' +import {Config} from '../../../src/RepositoryLinter/Config.js' describe('Config', function () { beforeEach(function () { diff --git a/packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js b/packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js index fd640bcd4..babc8691e 100644 --- a/packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js +++ b/packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js @@ -1,8 +1,8 @@ import {expect} from 'chai' import {spy, stub} from 'sinon' -import {Context} from '../../src/RepositoryLinter/Context.js' -import {Match} from '../../src/RepositoryLinter/Match.js' +import {Context} from '../../../src/RepositoryLinter/Context.js' +import {Match} from '../../../src/RepositoryLinter/Match.js' const LEVELS = { OFF: 0, diff --git a/packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js b/packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js index 5db0c60c7..e609d2e6e 100644 --- a/packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js +++ b/packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js @@ -1,7 +1,7 @@ import {expect} from 'chai' import {stub} from 'sinon' -import {CustomFileReader, Match} from '../../src/RepositoryLinter/Match.js' +import {CustomFileReader, Match} from '../../../src/RepositoryLinter/Match.js' describe('Match', function () { beforeEach(function () { diff --git a/packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js b/packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js index ad9cc62c5..3f40cecb6 100644 --- a/packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js +++ b/packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js @@ -2,7 +2,7 @@ import {expect} from 'chai' import {Table} from 'console-table-printer' import {stub} from 'sinon' -import {Results} from '../../src/RepositoryLinter/Results.js' +import {Results} from '../../../src/RepositoryLinter/Results.js' describe('Results', function () { beforeEach(function () { diff --git a/packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js b/packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js index 5d69d1e58..a1970002f 100644 --- a/packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js +++ b/packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js @@ -1,8 +1,8 @@ import {expect} from 'chai' import {stub} from 'sinon' -import {Match} from '../../src/RepositoryLinter/Match' -import {Runner} from '../../src/RepositoryLinter/Runner.js' +import {Match} from '../../../src/RepositoryLinter/Match.js' +import {Runner} from '../../../src/RepositoryLinter/Runner.js' describe('Runner', function () { beforeEach(function () { From df3de9f1daa4ec04f856c8d0812042385b626c81 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 18:04:55 +0100 Subject: [PATCH 26/47] test(packages/eslint-plugin-sui): move folder --- .../test/server/rules/factory-pattern.js | 41 -------- .../server/rules/serialize-deserialize.js | 96 ------------------- 2 files changed, 137 deletions(-) delete mode 100644 packages/eslint-plugin-sui/test/server/rules/factory-pattern.js delete mode 100644 packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js diff --git a/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js b/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js deleted file mode 100644 index 458134e3d..000000000 --- a/packages/eslint-plugin-sui/test/server/rules/factory-pattern.js +++ /dev/null @@ -1,41 +0,0 @@ -import dedent from 'dedent' -import {RuleTester} from 'eslint' - -import rule from '../../../src/rules/factory-pattern.js' - -// ------------------------------------------------------------------------------ -// Tests -// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester -// ------------------------------------------------------------------------------ - -const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) -ruleTester.run('factory-pattern', rule, { - valid: [ - { - code: dedent` - class User { - static create() { return new User() } - } - ` - } - ], - - invalid: [ - { - code: dedent` - class Model { - constructor() { this.name = 'John Doe' } - }`, - errors: [ - { - message: dedent` - You have to define at least one static function that return an instance of your class. - Avoid to use the 'new' keyword directly in your code. - Use always a factory function - `, - type: 'ClassDeclaration' - } - ] - } - ] -}) diff --git a/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js deleted file mode 100644 index e42234289..000000000 --- a/packages/eslint-plugin-sui/test/server/rules/serialize-deserialize.js +++ /dev/null @@ -1,96 +0,0 @@ -import dedent from 'dedent' -import {RuleTester} from 'eslint' - -import rule from '../../../src/rules/serialize-deserialize.js' - -// ------------------------------------------------------------------------------ -// Tests -// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester -// ------------------------------------------------------------------------------ - -const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) -ruleTester.run('serialize-deserialize', rule, { - valid: [ - { - code: dedent` - class User { - static create({id, name}) { return new User(id, name) } - constructor(id, name) { - this.id = id - this.name = name - } - toJSON() { - return { - id: this.id, - name: this.name - } - } - } - ` - } - ], - - invalid: [ - { - code: dedent` - class User { - static create({id, name}) { return new User(id, name) } - constructor(id, name) { - this.id = id - this.name = name - } - toJSON() { - return this.id - } - } - `, - errors: [ - { - message: dedent`toJSON should return an object` - } - ] - }, - { - code: dedent` - class User { - constructor(id, name) { - this.id = id - this.name = name - } - toJSON() { - return { - Noid: this.id, - Noname: this.name - } - } - } - `, - errors: [ - { - message: dedent` - If your class has a 'toJSON' method. You have to define a 'static create' method too. - The output of the 'toJSON' should be the same as the input of your 'static create' method - ` - } - ] - }, - { - code: dedent` - class User { - static create({id, name}) { return new User(id, name) } - constructor(id, name) { - this.id = id - this.name = name - } - toJSON() { - return { - Noid: this.id, - Noname: this.name - } - } - } - `, - errors: [{message: 'Missing toJSON properties (id, name)'}] - } - ] -}) From a704fc2914965f43229c22f5c1b3cea422173c4a Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 18:05:28 +0100 Subject: [PATCH 27/47] test(packages/lint-repository-sui): move folder --- .../test/server/rules/github-actionSpec.js | 53 ------------------- .../test/server/rules/node-versionSpec.js | 44 --------------- .../test/server/rules/package-lockSpec.js | 25 --------- .../test/server/rules/react-versionSpec.js | 44 --------------- 4 files changed, 166 deletions(-) delete mode 100644 packages/lint-repository-sui/test/server/rules/github-actionSpec.js delete mode 100644 packages/lint-repository-sui/test/server/rules/node-versionSpec.js delete mode 100644 packages/lint-repository-sui/test/server/rules/package-lockSpec.js delete mode 100644 packages/lint-repository-sui/test/server/rules/react-versionSpec.js diff --git a/packages/lint-repository-sui/test/server/rules/github-actionSpec.js b/packages/lint-repository-sui/test/server/rules/github-actionSpec.js deleted file mode 100644 index 67f21665a..000000000 --- a/packages/lint-repository-sui/test/server/rules/github-actionSpec.js +++ /dev/null @@ -1,53 +0,0 @@ -import dedent from 'dedent' - -import handler from '../../../src/rules/github-action.js' -import {RuleTester} from '../../TestHelpers.js' - -RuleTester.create('github-action', handler).run({ - valid: [ - { - '.github/workflows': [], - name: 'The porject has define a worflows folder', - monitoring: true - }, - { - '.github/**/main.yml': [], - name: 'The porject has define a worflow for the main branch', - monitoring: true - }, - { - '.github/**/pullrequest.yml': [], - name: 'The porject has define a worflow for PRs', - monitoring: true - } - ], - invalid: [ - { - missmatch: '.github/workflows', - name: 'The porject has NOT define a worflows folder', - report: dedent` - Every project needs to have a .github/worflows folder to be able to run CI/CD in GHA. - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: false - }, - { - missmatch: '.github/**/main.yml', - name: 'The porject has NOT define a worflow for the main branch', - report: dedent` - Every project needs to have a workflow to run on master. - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: false - }, - { - missmatch: '.github/**/pullrequest.yml', - name: 'The porject has NOT define a worflow for PRs', - report: dedent` - Every project needs to have a workflow to run on every PR. - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: false - } - ] -}) diff --git a/packages/lint-repository-sui/test/server/rules/node-versionSpec.js b/packages/lint-repository-sui/test/server/rules/node-versionSpec.js deleted file mode 100644 index 242ee636d..000000000 --- a/packages/lint-repository-sui/test/server/rules/node-versionSpec.js +++ /dev/null @@ -1,44 +0,0 @@ -import dedent from 'dedent' - -import handler from '../../../src/rules/node-version.js' -import {MatchStub, RuleTester} from '../../TestHelpers.js' - -RuleTester.create('node-version', handler).run({ - valid: [ - { - '.nvmrc': [MatchStub.create({raw: '20'})], - name: 'nvmrc Exists and has setup the version 20', - monitoring: '20' - } - ], - invalid: [ - { - '.nvmrc': [MatchStub.create({raw: '20'}), MatchStub.create({raw: 17})], - name: 'Exits more than one nvmrc file', - report: dedent` - Your project has more than one .nvmrc file. That can be dangerous. - Please, use onle ONE in the root of your project. - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: 0 - }, - { - '.nvmrc': [MatchStub.create({raw: '16'})], - name: 'Exits more than one nvmrc file', - report: dedent` - Your current Node version is 16. - Please be sure that your repository use the latest Node Version 20. - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: 0 - }, - { - missmatch: '', - report: dedent` - Every project have to have a .npmrc file to define the node versión. - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: 0 - } - ] -}) diff --git a/packages/lint-repository-sui/test/server/rules/package-lockSpec.js b/packages/lint-repository-sui/test/server/rules/package-lockSpec.js deleted file mode 100644 index 6684cfc4e..000000000 --- a/packages/lint-repository-sui/test/server/rules/package-lockSpec.js +++ /dev/null @@ -1,25 +0,0 @@ -import dedent from 'dedent' - -import handler from '../../../src/rules/package-lock.js' -import {RuleTester} from '../../TestHelpers.js' - -RuleTester.create('package-lock', handler).run({ - valid: [ - { - 'package-lock.json': [], - name: 'Project has package-lock.json in the root folder', - monitoring: true - } - ], - invalid: [ - { - missmatch: '', - name: 'Project doesnt has package-lock in the root folder', - report: dedent` - Every project needs to have a package-lock.json file to be used in CI/CD. - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: false - } - ] -}) diff --git a/packages/lint-repository-sui/test/server/rules/react-versionSpec.js b/packages/lint-repository-sui/test/server/rules/react-versionSpec.js deleted file mode 100644 index abb63b6ca..000000000 --- a/packages/lint-repository-sui/test/server/rules/react-versionSpec.js +++ /dev/null @@ -1,44 +0,0 @@ -import dedent from 'dedent' - -import handler from '../../../src/rules/react-version.js' -import {MatchStub, RuleTester} from '../../TestHelpers.js' - -RuleTester.create('react-version', handler).run({ - valid: [ - { - 'package-lock.json': [MatchStub.create({parsed: {packages: {'node_modules/react': {version: '18.0.0'}}}})], - name: 'React 18 installed', - monitoring: '18' - } - ], - invalid: [ - { - 'package-lock.json': [MatchStub.create({parsed: {packages: {}}})], - name: 'React not installed', - report: dedent` - Your project doesnt have installed React. - Please install at least the version 18. - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: 0 - }, - { - 'package-lock.json': [MatchStub.create({parsed: {packages: {'node_modules/react': {version: '17.0.0'}}}})], - name: 'React wrong version', - report: dedent` - Please be sure that your repository use the latest React Version 18. - Your current version is 17. - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: '17' - }, - { - missmatch: '', - report: dedent` - To calculate the react version first we need to have a package-lock.json in the root - If you are not sure about how do it, please contact with Platform Web. - `, - monitoring: 0 - } - ] -}) From 4b029c895841c095a793fe61def8bbb747c526f6 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 18:06:10 +0100 Subject: [PATCH 28/47] test(packages/sui-lint): move folder --- .../server/RepositoryLinter/ConfigSpec.js | 38 ---- .../server/RepositoryLinter/ContextSpec.js | 206 ------------------ .../test/server/RepositoryLinter/MatchSpec.js | 99 --------- .../server/RepositoryLinter/ResultsSpec.js | 83 ------- .../server/RepositoryLinter/RunnerSpec.js | 26 --- 5 files changed, 452 deletions(-) delete mode 100644 packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js delete mode 100644 packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js delete mode 100644 packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js delete mode 100644 packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js delete mode 100644 packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js diff --git a/packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js b/packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js deleted file mode 100644 index 0261735b2..000000000 --- a/packages/sui-lint/test/server/RepositoryLinter/ConfigSpec.js +++ /dev/null @@ -1,38 +0,0 @@ -import {expect} from 'chai' -import {stub} from 'sinon' - -import {Config} from '../../../src/RepositoryLinter/Config.js' - -describe('Config', function () { - beforeEach(function () { - this.requireConfigStub = stub(Config.prototype, 'requireConfig') - this.requirePkgStub = stub(Config.prototype, 'requirePkg') - }) - - afterEach(function () { - this.requireConfigStub.reset() - this.requirePkgStub.reset() - }) - - it('Should return a rules object', async function () { - // Given - const handler = { - meta: {messages: {badVersion: 'Your react version is not 20'}}, - create: function () {} - } - this.requireConfigStub.returns({ - plugins: ['tester'], - rules: { - 'tester/react-version': 1 - } - }) - this.requirePkgStub.returns({rules: {'react-version': handler}}) - - // When - const rulesLoaded = await Config.create().load() - - // Then - expect(this.requirePkgStub.calledWith('tester')).to.be.eql(true) - expect(rulesLoaded).to.be.eqls({'tester/react-version': {handler, level: 1}}) - }) -}) diff --git a/packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js b/packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js deleted file mode 100644 index babc8691e..000000000 --- a/packages/sui-lint/test/server/RepositoryLinter/ContextSpec.js +++ /dev/null @@ -1,206 +0,0 @@ -import {expect} from 'chai' -import {spy, stub} from 'sinon' - -import {Context} from '../../../src/RepositoryLinter/Context.js' -import {Match} from '../../../src/RepositoryLinter/Match.js' - -const LEVELS = { - OFF: 0, - WARNING: 1, - ERROR: 2 -} - -describe('Context', function () { - beforeEach(function () { - this.reportSpy = spy(Context.prototype, 'report') - this.monitoringSpy = spy(Context.prototype, 'monitoring') - this.runnerStub = {assertion: stub()} - this.handlerStub = { - meta: {messages: {badVersion: 'Message for your bad version'}}, - __assertionStub: stub(), - __missmatchStub: stub(), - create() { - return { - 'package.json': this.__assertionStub, - missmatch: this.__missmatchStub - } - } - } - - this.handlerInnerStub = { - meta: {messages: {badVersion: 'Message for your bad version', badKey: 'Message for bad {{key}}'}}, - create(context) { - return { - 'package.json': matches => { - context.report({messageId: 'badVersion'}) - context.monitoring(true) - }, - missmatch: key => { - context.report({messageId: 'badKey', data: {key}}) - context.monitoring(false) - } - } - } - } - - this.handlerReducerMonitoringStub = { - meta: {messages: {badVersion: 'Message for your bad version', badKey: 'Message for bad {{key}}'}}, - reduceMonitoring: stub(), - create(context) { - return { - 'package.json': matches => { - context.monitoring(true) - context.monitoring(false) - } - } - } - } - }) - - afterEach(function () { - this.handlerStub.__assertionStub.reset() - this.handlerStub.__missmatchStub.reset() - - this.monitoringSpy.restore() - this.reportSpy.restore() - - this.runnerStub.assertion.reset() - - this.handlerReducerMonitoringStub.reduceMonitoring?.reset() - }) - - it('Should call to the assertions in the handler when there is Match', function () { - // Given - const emptyMatch = Match.empty() - this.runnerStub.assertion.returns([emptyMatch]) - - // When - Context.create(LEVELS.WARNING, this.handlerStub, 'tests/node-version', this.runnerStub).run() - - // Then - expect(this.handlerStub.__assertionStub.firstCall.firstArg).to.be.instanceof(Array) - expect(this.handlerStub.__assertionStub.firstCall.firstArg[0]).to.be.eql(emptyMatch) - }) - - it('Should call to the missmatch in the handler when there is not Match with the "failing" key', function () { - // Given - this.runnerStub.assertion.returns([]) - - // When - Context.create(LEVELS.WARNING, this.handlerStub, 'tests/node-version', this.runnerStub).run() - - // Then - expect(this.handlerStub.__assertionStub.firstCall).to.be.eql(null) - expect(this.handlerStub.__missmatchStub.firstCall.firstArg).to.be.eql('package.json') - }) - - it('Should create new monitorings and messages from assertion function', function () { - // Given - this.runnerStub.assertion.returns([Match.empty()]) - - // When - Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() - - // Then - expect(this.reportSpy.firstCall.firstArg).to.be.eql({messageId: 'badVersion'}) - expect(this.monitoringSpy.firstCall.firstArg).to.be.eql(true) - }) - - it('Should create new monitorings and messages from missmatch function', function () { - // Given - this.runnerStub.assertion.returns([]) - - // When - Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() - - // Then - expect(this.reportSpy.firstCall.firstArg).to.be.eql({messageId: 'badKey', data: {key: 'package.json'}}) - expect(this.monitoringSpy.firstCall.firstArg).to.be.eql(false) - }) - - it('Should properly format the messages', function () { - // Given - this.runnerStub.assertion.returns([]) - - // When - const context = Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() - - // Then - expect(context.messages).to.be.eql([ - { - rule: 'tests/node-version', - message: 'Message for bad package.json', - level: 1, - messageId: 'badKey', - data: {key: 'package.json'} - } - ]) - }) - - it('Should properly format the monitoring', function () { - // Given - this.runnerStub.assertion.returns([Match.empty()]) - - // When - const context = Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() - - // Then - expect(context.signal).to.be.eql({ - rule: 'tests/node-version', - value: true, - level: 1 - }) - }) - - it('Should require a reduceMonitoring function when there are more than one monitor', function () { - // Given - this.runnerStub.assertion.returns([Match.empty()]) - this.handlerReducerMonitoringStub.reduceMonitoring.returns(false) - - // When - const context = Context.create( - LEVELS.WARNING, - this.handlerReducerMonitoringStub, - 'tests/node-version', - this.runnerStub - ).run() - - // Then - expect(context.signal).to.be.eql({ - rule: 'tests/node-version', - value: false, - level: 1 - }) - expect(this.handlerReducerMonitoringStub.reduceMonitoring.firstCall.firstArg).to.be.eql([ - { - assertion: 'package.json', - rule: 'tests/node-version', - value: true, - level: 1 - }, - { - assertion: 'package.json', - rule: 'tests/node-version', - value: false, - level: 1 - } - ]) - }) - - it('Should throw an exception if the reduceMonitoring function is undefined', function () { - // Given - this.runnerStub.assertion.returns([Match.empty()]) - delete this.handlerReducerMonitoringStub.reduceMonitoring - - // When - const context = Context.create( - LEVELS.WARNING, - this.handlerReducerMonitoringStub, - 'tests/node-version', - this.runnerStub - ).run() - - // Then - expect(() => context.signal).to.be.throw(Context.MISSING_REDUCER_MONITORING_MSG) - }) -}) diff --git a/packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js b/packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js deleted file mode 100644 index e609d2e6e..000000000 --- a/packages/sui-lint/test/server/RepositoryLinter/MatchSpec.js +++ /dev/null @@ -1,99 +0,0 @@ -import {expect} from 'chai' -import {stub} from 'sinon' - -import {CustomFileReader, Match} from '../../../src/RepositoryLinter/Match.js' - -describe('Match', function () { - beforeEach(function () { - this.isDirStub = stub(CustomFileReader.prototype, 'isDirectory') - - this.parseYMLStub = stub(CustomFileReader.prototype, 'parseYML') - this.parseJSONStub = stub(CustomFileReader.prototype, 'parseJSON') - this.rawStub = stub(CustomFileReader.prototype, 'raw') - }) - - afterEach(function () { - this.isDirStub.restore() - - this.parseYMLStub.restore() - this.parseJSONStub.restore() - this.rawStub.restore() - }) - - it('Should detect directories', function () { - // Given - this.isDirStub.returns(true) - - // When - const match = Match.create('/dir/path') - - // Then - expect(match.isDir).to.be.eqls(true) - }) - - it('Should detect files w/out extensions', function () { - // Given - this.isDirStub.returns(false) - this.rawStub.returns('20') - - // When - const match = Match.create('/dir/path') - - // Then - expect(match.isDir).to.be.eqls(false) - expect(this.rawStub.calledWith('/dir/path')).to.be.eql(true) - }) - - it('Should parse JSON files', function () { - // Given - this.isDirStub.returns(false) - this.parseJSONStub.returns({a: 1}) - - // When - const match = Match.create('/dir/file.json') - - // Then - expect(match.parsed).to.be.eqls({a: 1}) - expect(this.parseJSONStub.calledWith('/dir/file.json')).to.be.eql(true) - }) - - it('Should parse yml files', function () { - // Given - this.isDirStub.returns(false) - this.parseYMLStub.returns({a: 1}) - - // When - const match = Match.create('/dir/file.yml') - - // Then - expect(match.parsed).to.be.eqls({a: 1}) - expect(this.parseYMLStub.calledWith('/dir/file.yml')).to.be.eql(true) - }) - - it('Should parse yaml files', function () { - // Given - this.isDirStub.returns(false) - this.parseYMLStub.returns({a: 1}) - - // When - const match = Match.create('/dir/file.yaml') - - // Then - expect(match.parsed).to.be.eqls({a: 1}) - expect(this.parseYMLStub.calledWith('/dir/file.yaml')).to.be.eql(true) - }) - - it('Should read unkown files', function () { - // Given - this.isDirStub.returns(false) - this.rawStub.returns('Hello') - - // When - const match = Match.create('/dir/file.txt') - - // Then - expect(match.raw).to.be.eqls('Hello') - expect(match.parsed).to.be.eqls(undefined) - expect(this.rawStub.calledWith('/dir/file.txt')).to.be.eql(true) - }) -}) diff --git a/packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js b/packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js deleted file mode 100644 index 3f40cecb6..000000000 --- a/packages/sui-lint/test/server/RepositoryLinter/ResultsSpec.js +++ /dev/null @@ -1,83 +0,0 @@ -import {expect} from 'chai' -import {Table} from 'console-table-printer' -import {stub} from 'sinon' - -import {Results} from '../../../src/RepositoryLinter/Results.js' - -describe('Results', function () { - beforeEach(function () { - this.addRowStub = stub(Table.prototype, 'addRow') - this.printTableStub = stub(Table.prototype, 'printTable') - - this.logStub = stub(Results.prototype, 'log') - }) - - afterEach(function () { - this.addRowStub.restore() - this.printTableStub.restore() - - this.logStub.restore() - }) - - it('Should print Happy Message it there is not messages', function () { - const executions = [ - { - messages: [], - signal: false - } - ] - Results.create(executions).logTable() - - expect(this.logStub.calledWith(Results.HAPPY_MESSAGE)).to.be.eq(true) - }) - - it('Should print a table with all the messages', function () { - const executions = [ - {messages: [{rule: 'tester/node-version', message: 'Node version fail', level: 1}], signal: 12}, - {messages: [{rule: 'tester/react-version', message: 'React version fail', level: 2}], signal: 17}, - {messages: [], signal: true} - ] - Results.create(executions).logTable() - - expect(this.addRowStub.firstCall.firstArg).to.be.eql({rule: 'tester/node-version', message: 'Node version fail'}) - expect(this.addRowStub.firstCall.lastArg).to.be.eql({color: 'yellow'}) - - expect(this.addRowStub.secondCall.firstArg).to.be.eql({rule: 'tester/react-version', message: 'React version fail'}) - expect(this.addRowStub.secondCall.lastArg).to.be.eql({color: 'red'}) - }) - - it('Should print a table with all the monitorings', function () { - const executions = [ - {messages: [{rule: 'tester/node-version', message: 'Node version fail', level: 1}], signal: 12}, - {messages: [{rule: 'tester/react-version', message: 'React version fail', level: 2}], signal: 17}, - {messages: [], signal: true} - ] - Results.create(executions).logMonitorings() - - expect(this.addRowStub.firstCall.firstArg).to.be.eql(12) - expect(this.addRowStub.secondCall.firstArg).to.be.eql(17) - expect(this.addRowStub.thirdCall.firstArg).to.be.eql(true) - }) - - it('Should print a JSON output', function () { - const executions = [ - {messages: [{rule: 'tester/node-version', message: 'Node version fail', level: 1}], signal: 12}, - {messages: [{rule: 'tester/react-version', message: 'React version fail', level: 2}], signal: 17}, - {messages: [], signal: true} - ] - Results.create(executions).logJSON() - - expect( - this.logStub.calledWith( - JSON.stringify( - [ - {rule: 'tester/node-version', message: 'Node version fail', level: 1}, - {rule: 'tester/react-version', message: 'React version fail', level: 2} - ], - null, - 2 - ) - ) - ).to.be.eq(true) - }) -}) diff --git a/packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js b/packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js deleted file mode 100644 index a1970002f..000000000 --- a/packages/sui-lint/test/server/RepositoryLinter/RunnerSpec.js +++ /dev/null @@ -1,26 +0,0 @@ -import {expect} from 'chai' -import {stub} from 'sinon' - -import {Match} from '../../../src/RepositoryLinter/Match.js' -import {Runner} from '../../../src/RepositoryLinter/Runner.js' - -describe('Runner', function () { - beforeEach(function () { - this.syncStub = stub() - this.matchCreateStub = stub(Match, 'create') - }) - - afterEach(function () { - this.syncStub.reset() - this.matchCreateStub.restore() - }) - - it('Should return a list of matches', function () { - this.syncStub.returns(['path/file.json']) - - Runner.create({sync: this.syncStub}).assertion('**/*.json') - - expect(this.matchCreateStub.firstCall.firstArg).to.be.eql('path/file.json') - expect(this.syncStub.firstCall.firstArg).to.be.eql('**/*.json') - }) -}) From 176eeafd0f966f834cd9c29fedb2494e708184f0 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Mon, 4 Mar 2024 18:07:02 +0100 Subject: [PATCH 29/47] test(Root): move folder --- .../test/server/factory-pattern.js | 41 ++++ .../test/server/serialize-deserialize.js | 96 ++++++++ .../test/server/github-actionSpec.js | 53 +++++ .../test/server/node-versionSpec.js | 44 ++++ .../test/server/package-lockSpec.js | 25 +++ .../test/server/react-versionSpec.js | 44 ++++ packages/sui-lint/test/server/ConfigSpec.js | 38 ++++ packages/sui-lint/test/server/ContextSpec.js | 206 ++++++++++++++++++ packages/sui-lint/test/server/MatchSpec.js | 99 +++++++++ packages/sui-lint/test/server/ResultsSpec.js | 83 +++++++ packages/sui-lint/test/server/RunnerSpec.js | 26 +++ 11 files changed, 755 insertions(+) create mode 100644 packages/eslint-plugin-sui/test/server/factory-pattern.js create mode 100644 packages/eslint-plugin-sui/test/server/serialize-deserialize.js create mode 100644 packages/lint-repository-sui/test/server/github-actionSpec.js create mode 100644 packages/lint-repository-sui/test/server/node-versionSpec.js create mode 100644 packages/lint-repository-sui/test/server/package-lockSpec.js create mode 100644 packages/lint-repository-sui/test/server/react-versionSpec.js create mode 100644 packages/sui-lint/test/server/ConfigSpec.js create mode 100644 packages/sui-lint/test/server/ContextSpec.js create mode 100644 packages/sui-lint/test/server/MatchSpec.js create mode 100644 packages/sui-lint/test/server/ResultsSpec.js create mode 100644 packages/sui-lint/test/server/RunnerSpec.js diff --git a/packages/eslint-plugin-sui/test/server/factory-pattern.js b/packages/eslint-plugin-sui/test/server/factory-pattern.js new file mode 100644 index 000000000..2e63d949a --- /dev/null +++ b/packages/eslint-plugin-sui/test/server/factory-pattern.js @@ -0,0 +1,41 @@ +import dedent from 'dedent' +import {RuleTester} from 'eslint' + +import rule from '../../src/rules/factory-pattern.js' + +// ------------------------------------------------------------------------------ +// Tests +// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) +ruleTester.run('factory-pattern', rule, { + valid: [ + { + code: dedent` + class User { + static create() { return new User() } + } + ` + } + ], + + invalid: [ + { + code: dedent` + class Model { + constructor() { this.name = 'John Doe' } + }`, + errors: [ + { + message: dedent` + You have to define at least one static function that return an instance of your class. + Avoid to use the 'new' keyword directly in your code. + Use always a factory function + `, + type: 'ClassDeclaration' + } + ] + } + ] +}) diff --git a/packages/eslint-plugin-sui/test/server/serialize-deserialize.js b/packages/eslint-plugin-sui/test/server/serialize-deserialize.js new file mode 100644 index 000000000..e5fd6d925 --- /dev/null +++ b/packages/eslint-plugin-sui/test/server/serialize-deserialize.js @@ -0,0 +1,96 @@ +import dedent from 'dedent' +import {RuleTester} from 'eslint' + +import rule from '../../src/rules/serialize-deserialize.js' + +// ------------------------------------------------------------------------------ +// Tests +// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) +ruleTester.run('serialize-deserialize', rule, { + valid: [ + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + id: this.id, + name: this.name + } + } + } + ` + } + ], + + invalid: [ + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return this.id + } + } + `, + errors: [ + { + message: dedent`toJSON should return an object` + } + ] + }, + { + code: dedent` + class User { + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + Noid: this.id, + Noname: this.name + } + } + } + `, + errors: [ + { + message: dedent` + If your class has a 'toJSON' method. You have to define a 'static create' method too. + The output of the 'toJSON' should be the same as the input of your 'static create' method + ` + } + ] + }, + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + Noid: this.id, + Noname: this.name + } + } + } + `, + errors: [{message: 'Missing toJSON properties (id, name)'}] + } + ] +}) diff --git a/packages/lint-repository-sui/test/server/github-actionSpec.js b/packages/lint-repository-sui/test/server/github-actionSpec.js new file mode 100644 index 000000000..346cf8e42 --- /dev/null +++ b/packages/lint-repository-sui/test/server/github-actionSpec.js @@ -0,0 +1,53 @@ +import dedent from 'dedent' + +import handler from '../../src/rules/github-action.js' +import {RuleTester} from '../TestHelpers.js' + +RuleTester.create('github-action', handler).run({ + valid: [ + { + '.github/workflows': [], + name: 'The porject has define a worflows folder', + monitoring: true + }, + { + '.github/**/main.yml': [], + name: 'The porject has define a worflow for the main branch', + monitoring: true + }, + { + '.github/**/pullrequest.yml': [], + name: 'The porject has define a worflow for PRs', + monitoring: true + } + ], + invalid: [ + { + missmatch: '.github/workflows', + name: 'The porject has NOT define a worflows folder', + report: dedent` + Every project needs to have a .github/worflows folder to be able to run CI/CD in GHA. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: false + }, + { + missmatch: '.github/**/main.yml', + name: 'The porject has NOT define a worflow for the main branch', + report: dedent` + Every project needs to have a workflow to run on master. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: false + }, + { + missmatch: '.github/**/pullrequest.yml', + name: 'The porject has NOT define a worflow for PRs', + report: dedent` + Every project needs to have a workflow to run on every PR. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: false + } + ] +}) diff --git a/packages/lint-repository-sui/test/server/node-versionSpec.js b/packages/lint-repository-sui/test/server/node-versionSpec.js new file mode 100644 index 000000000..c113232b9 --- /dev/null +++ b/packages/lint-repository-sui/test/server/node-versionSpec.js @@ -0,0 +1,44 @@ +import dedent from 'dedent' + +import handler from '../../src/rules/node-version.js' +import {MatchStub, RuleTester} from '../TestHelpers.js' + +RuleTester.create('node-version', handler).run({ + valid: [ + { + '.nvmrc': [MatchStub.create({raw: '20'})], + name: 'nvmrc Exists and has setup the version 20', + monitoring: '20' + } + ], + invalid: [ + { + '.nvmrc': [MatchStub.create({raw: '20'}), MatchStub.create({raw: 17})], + name: 'Exits more than one nvmrc file', + report: dedent` + Your project has more than one .nvmrc file. That can be dangerous. + Please, use onle ONE in the root of your project. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + }, + { + '.nvmrc': [MatchStub.create({raw: '16'})], + name: 'Exits more than one nvmrc file', + report: dedent` + Your current Node version is 16. + Please be sure that your repository use the latest Node Version 20. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + }, + { + missmatch: '', + report: dedent` + Every project have to have a .npmrc file to define the node versión. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + } + ] +}) diff --git a/packages/lint-repository-sui/test/server/package-lockSpec.js b/packages/lint-repository-sui/test/server/package-lockSpec.js new file mode 100644 index 000000000..92773f311 --- /dev/null +++ b/packages/lint-repository-sui/test/server/package-lockSpec.js @@ -0,0 +1,25 @@ +import dedent from 'dedent' + +import handler from '../../src/rules/package-lock.js' +import {RuleTester} from '../TestHelpers.js' + +RuleTester.create('package-lock', handler).run({ + valid: [ + { + 'package-lock.json': [], + name: 'Project has package-lock.json in the root folder', + monitoring: true + } + ], + invalid: [ + { + missmatch: '', + name: 'Project doesnt has package-lock in the root folder', + report: dedent` + Every project needs to have a package-lock.json file to be used in CI/CD. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: false + } + ] +}) diff --git a/packages/lint-repository-sui/test/server/react-versionSpec.js b/packages/lint-repository-sui/test/server/react-versionSpec.js new file mode 100644 index 000000000..6f3ceded4 --- /dev/null +++ b/packages/lint-repository-sui/test/server/react-versionSpec.js @@ -0,0 +1,44 @@ +import dedent from 'dedent' + +import handler from '../../src/rules/react-version.js' +import {MatchStub, RuleTester} from '../TestHelpers.js' + +RuleTester.create('react-version', handler).run({ + valid: [ + { + 'package-lock.json': [MatchStub.create({parsed: {packages: {'node_modules/react': {version: '18.0.0'}}}})], + name: 'React 18 installed', + monitoring: '18' + } + ], + invalid: [ + { + 'package-lock.json': [MatchStub.create({parsed: {packages: {}}})], + name: 'React not installed', + report: dedent` + Your project doesnt have installed React. + Please install at least the version 18. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + }, + { + 'package-lock.json': [MatchStub.create({parsed: {packages: {'node_modules/react': {version: '17.0.0'}}}})], + name: 'React wrong version', + report: dedent` + Please be sure that your repository use the latest React Version 18. + Your current version is 17. + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: '17' + }, + { + missmatch: '', + report: dedent` + To calculate the react version first we need to have a package-lock.json in the root + If you are not sure about how do it, please contact with Platform Web. + `, + monitoring: 0 + } + ] +}) diff --git a/packages/sui-lint/test/server/ConfigSpec.js b/packages/sui-lint/test/server/ConfigSpec.js new file mode 100644 index 000000000..0261735b2 --- /dev/null +++ b/packages/sui-lint/test/server/ConfigSpec.js @@ -0,0 +1,38 @@ +import {expect} from 'chai' +import {stub} from 'sinon' + +import {Config} from '../../../src/RepositoryLinter/Config.js' + +describe('Config', function () { + beforeEach(function () { + this.requireConfigStub = stub(Config.prototype, 'requireConfig') + this.requirePkgStub = stub(Config.prototype, 'requirePkg') + }) + + afterEach(function () { + this.requireConfigStub.reset() + this.requirePkgStub.reset() + }) + + it('Should return a rules object', async function () { + // Given + const handler = { + meta: {messages: {badVersion: 'Your react version is not 20'}}, + create: function () {} + } + this.requireConfigStub.returns({ + plugins: ['tester'], + rules: { + 'tester/react-version': 1 + } + }) + this.requirePkgStub.returns({rules: {'react-version': handler}}) + + // When + const rulesLoaded = await Config.create().load() + + // Then + expect(this.requirePkgStub.calledWith('tester')).to.be.eql(true) + expect(rulesLoaded).to.be.eqls({'tester/react-version': {handler, level: 1}}) + }) +}) diff --git a/packages/sui-lint/test/server/ContextSpec.js b/packages/sui-lint/test/server/ContextSpec.js new file mode 100644 index 000000000..fd640bcd4 --- /dev/null +++ b/packages/sui-lint/test/server/ContextSpec.js @@ -0,0 +1,206 @@ +import {expect} from 'chai' +import {spy, stub} from 'sinon' + +import {Context} from '../../src/RepositoryLinter/Context.js' +import {Match} from '../../src/RepositoryLinter/Match.js' + +const LEVELS = { + OFF: 0, + WARNING: 1, + ERROR: 2 +} + +describe('Context', function () { + beforeEach(function () { + this.reportSpy = spy(Context.prototype, 'report') + this.monitoringSpy = spy(Context.prototype, 'monitoring') + this.runnerStub = {assertion: stub()} + this.handlerStub = { + meta: {messages: {badVersion: 'Message for your bad version'}}, + __assertionStub: stub(), + __missmatchStub: stub(), + create() { + return { + 'package.json': this.__assertionStub, + missmatch: this.__missmatchStub + } + } + } + + this.handlerInnerStub = { + meta: {messages: {badVersion: 'Message for your bad version', badKey: 'Message for bad {{key}}'}}, + create(context) { + return { + 'package.json': matches => { + context.report({messageId: 'badVersion'}) + context.monitoring(true) + }, + missmatch: key => { + context.report({messageId: 'badKey', data: {key}}) + context.monitoring(false) + } + } + } + } + + this.handlerReducerMonitoringStub = { + meta: {messages: {badVersion: 'Message for your bad version', badKey: 'Message for bad {{key}}'}}, + reduceMonitoring: stub(), + create(context) { + return { + 'package.json': matches => { + context.monitoring(true) + context.monitoring(false) + } + } + } + } + }) + + afterEach(function () { + this.handlerStub.__assertionStub.reset() + this.handlerStub.__missmatchStub.reset() + + this.monitoringSpy.restore() + this.reportSpy.restore() + + this.runnerStub.assertion.reset() + + this.handlerReducerMonitoringStub.reduceMonitoring?.reset() + }) + + it('Should call to the assertions in the handler when there is Match', function () { + // Given + const emptyMatch = Match.empty() + this.runnerStub.assertion.returns([emptyMatch]) + + // When + Context.create(LEVELS.WARNING, this.handlerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(this.handlerStub.__assertionStub.firstCall.firstArg).to.be.instanceof(Array) + expect(this.handlerStub.__assertionStub.firstCall.firstArg[0]).to.be.eql(emptyMatch) + }) + + it('Should call to the missmatch in the handler when there is not Match with the "failing" key', function () { + // Given + this.runnerStub.assertion.returns([]) + + // When + Context.create(LEVELS.WARNING, this.handlerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(this.handlerStub.__assertionStub.firstCall).to.be.eql(null) + expect(this.handlerStub.__missmatchStub.firstCall.firstArg).to.be.eql('package.json') + }) + + it('Should create new monitorings and messages from assertion function', function () { + // Given + this.runnerStub.assertion.returns([Match.empty()]) + + // When + Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(this.reportSpy.firstCall.firstArg).to.be.eql({messageId: 'badVersion'}) + expect(this.monitoringSpy.firstCall.firstArg).to.be.eql(true) + }) + + it('Should create new monitorings and messages from missmatch function', function () { + // Given + this.runnerStub.assertion.returns([]) + + // When + Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(this.reportSpy.firstCall.firstArg).to.be.eql({messageId: 'badKey', data: {key: 'package.json'}}) + expect(this.monitoringSpy.firstCall.firstArg).to.be.eql(false) + }) + + it('Should properly format the messages', function () { + // Given + this.runnerStub.assertion.returns([]) + + // When + const context = Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(context.messages).to.be.eql([ + { + rule: 'tests/node-version', + message: 'Message for bad package.json', + level: 1, + messageId: 'badKey', + data: {key: 'package.json'} + } + ]) + }) + + it('Should properly format the monitoring', function () { + // Given + this.runnerStub.assertion.returns([Match.empty()]) + + // When + const context = Context.create(LEVELS.WARNING, this.handlerInnerStub, 'tests/node-version', this.runnerStub).run() + + // Then + expect(context.signal).to.be.eql({ + rule: 'tests/node-version', + value: true, + level: 1 + }) + }) + + it('Should require a reduceMonitoring function when there are more than one monitor', function () { + // Given + this.runnerStub.assertion.returns([Match.empty()]) + this.handlerReducerMonitoringStub.reduceMonitoring.returns(false) + + // When + const context = Context.create( + LEVELS.WARNING, + this.handlerReducerMonitoringStub, + 'tests/node-version', + this.runnerStub + ).run() + + // Then + expect(context.signal).to.be.eql({ + rule: 'tests/node-version', + value: false, + level: 1 + }) + expect(this.handlerReducerMonitoringStub.reduceMonitoring.firstCall.firstArg).to.be.eql([ + { + assertion: 'package.json', + rule: 'tests/node-version', + value: true, + level: 1 + }, + { + assertion: 'package.json', + rule: 'tests/node-version', + value: false, + level: 1 + } + ]) + }) + + it('Should throw an exception if the reduceMonitoring function is undefined', function () { + // Given + this.runnerStub.assertion.returns([Match.empty()]) + delete this.handlerReducerMonitoringStub.reduceMonitoring + + // When + const context = Context.create( + LEVELS.WARNING, + this.handlerReducerMonitoringStub, + 'tests/node-version', + this.runnerStub + ).run() + + // Then + expect(() => context.signal).to.be.throw(Context.MISSING_REDUCER_MONITORING_MSG) + }) +}) diff --git a/packages/sui-lint/test/server/MatchSpec.js b/packages/sui-lint/test/server/MatchSpec.js new file mode 100644 index 000000000..5db0c60c7 --- /dev/null +++ b/packages/sui-lint/test/server/MatchSpec.js @@ -0,0 +1,99 @@ +import {expect} from 'chai' +import {stub} from 'sinon' + +import {CustomFileReader, Match} from '../../src/RepositoryLinter/Match.js' + +describe('Match', function () { + beforeEach(function () { + this.isDirStub = stub(CustomFileReader.prototype, 'isDirectory') + + this.parseYMLStub = stub(CustomFileReader.prototype, 'parseYML') + this.parseJSONStub = stub(CustomFileReader.prototype, 'parseJSON') + this.rawStub = stub(CustomFileReader.prototype, 'raw') + }) + + afterEach(function () { + this.isDirStub.restore() + + this.parseYMLStub.restore() + this.parseJSONStub.restore() + this.rawStub.restore() + }) + + it('Should detect directories', function () { + // Given + this.isDirStub.returns(true) + + // When + const match = Match.create('/dir/path') + + // Then + expect(match.isDir).to.be.eqls(true) + }) + + it('Should detect files w/out extensions', function () { + // Given + this.isDirStub.returns(false) + this.rawStub.returns('20') + + // When + const match = Match.create('/dir/path') + + // Then + expect(match.isDir).to.be.eqls(false) + expect(this.rawStub.calledWith('/dir/path')).to.be.eql(true) + }) + + it('Should parse JSON files', function () { + // Given + this.isDirStub.returns(false) + this.parseJSONStub.returns({a: 1}) + + // When + const match = Match.create('/dir/file.json') + + // Then + expect(match.parsed).to.be.eqls({a: 1}) + expect(this.parseJSONStub.calledWith('/dir/file.json')).to.be.eql(true) + }) + + it('Should parse yml files', function () { + // Given + this.isDirStub.returns(false) + this.parseYMLStub.returns({a: 1}) + + // When + const match = Match.create('/dir/file.yml') + + // Then + expect(match.parsed).to.be.eqls({a: 1}) + expect(this.parseYMLStub.calledWith('/dir/file.yml')).to.be.eql(true) + }) + + it('Should parse yaml files', function () { + // Given + this.isDirStub.returns(false) + this.parseYMLStub.returns({a: 1}) + + // When + const match = Match.create('/dir/file.yaml') + + // Then + expect(match.parsed).to.be.eqls({a: 1}) + expect(this.parseYMLStub.calledWith('/dir/file.yaml')).to.be.eql(true) + }) + + it('Should read unkown files', function () { + // Given + this.isDirStub.returns(false) + this.rawStub.returns('Hello') + + // When + const match = Match.create('/dir/file.txt') + + // Then + expect(match.raw).to.be.eqls('Hello') + expect(match.parsed).to.be.eqls(undefined) + expect(this.rawStub.calledWith('/dir/file.txt')).to.be.eql(true) + }) +}) diff --git a/packages/sui-lint/test/server/ResultsSpec.js b/packages/sui-lint/test/server/ResultsSpec.js new file mode 100644 index 000000000..ad9cc62c5 --- /dev/null +++ b/packages/sui-lint/test/server/ResultsSpec.js @@ -0,0 +1,83 @@ +import {expect} from 'chai' +import {Table} from 'console-table-printer' +import {stub} from 'sinon' + +import {Results} from '../../src/RepositoryLinter/Results.js' + +describe('Results', function () { + beforeEach(function () { + this.addRowStub = stub(Table.prototype, 'addRow') + this.printTableStub = stub(Table.prototype, 'printTable') + + this.logStub = stub(Results.prototype, 'log') + }) + + afterEach(function () { + this.addRowStub.restore() + this.printTableStub.restore() + + this.logStub.restore() + }) + + it('Should print Happy Message it there is not messages', function () { + const executions = [ + { + messages: [], + signal: false + } + ] + Results.create(executions).logTable() + + expect(this.logStub.calledWith(Results.HAPPY_MESSAGE)).to.be.eq(true) + }) + + it('Should print a table with all the messages', function () { + const executions = [ + {messages: [{rule: 'tester/node-version', message: 'Node version fail', level: 1}], signal: 12}, + {messages: [{rule: 'tester/react-version', message: 'React version fail', level: 2}], signal: 17}, + {messages: [], signal: true} + ] + Results.create(executions).logTable() + + expect(this.addRowStub.firstCall.firstArg).to.be.eql({rule: 'tester/node-version', message: 'Node version fail'}) + expect(this.addRowStub.firstCall.lastArg).to.be.eql({color: 'yellow'}) + + expect(this.addRowStub.secondCall.firstArg).to.be.eql({rule: 'tester/react-version', message: 'React version fail'}) + expect(this.addRowStub.secondCall.lastArg).to.be.eql({color: 'red'}) + }) + + it('Should print a table with all the monitorings', function () { + const executions = [ + {messages: [{rule: 'tester/node-version', message: 'Node version fail', level: 1}], signal: 12}, + {messages: [{rule: 'tester/react-version', message: 'React version fail', level: 2}], signal: 17}, + {messages: [], signal: true} + ] + Results.create(executions).logMonitorings() + + expect(this.addRowStub.firstCall.firstArg).to.be.eql(12) + expect(this.addRowStub.secondCall.firstArg).to.be.eql(17) + expect(this.addRowStub.thirdCall.firstArg).to.be.eql(true) + }) + + it('Should print a JSON output', function () { + const executions = [ + {messages: [{rule: 'tester/node-version', message: 'Node version fail', level: 1}], signal: 12}, + {messages: [{rule: 'tester/react-version', message: 'React version fail', level: 2}], signal: 17}, + {messages: [], signal: true} + ] + Results.create(executions).logJSON() + + expect( + this.logStub.calledWith( + JSON.stringify( + [ + {rule: 'tester/node-version', message: 'Node version fail', level: 1}, + {rule: 'tester/react-version', message: 'React version fail', level: 2} + ], + null, + 2 + ) + ) + ).to.be.eq(true) + }) +}) diff --git a/packages/sui-lint/test/server/RunnerSpec.js b/packages/sui-lint/test/server/RunnerSpec.js new file mode 100644 index 000000000..282c75406 --- /dev/null +++ b/packages/sui-lint/test/server/RunnerSpec.js @@ -0,0 +1,26 @@ +import {expect} from 'chai' +import {stub} from 'sinon' + +import {Match} from '../../src/RepositoryLinter/Match.js' +import {Runner} from '../../src/RepositoryLinter/Runner.js' + +describe('Runner', function () { + beforeEach(function () { + this.syncStub = stub() + this.matchCreateStub = stub(Match, 'create') + }) + + afterEach(function () { + this.syncStub.reset() + this.matchCreateStub.restore() + }) + + it('Should return a list of matches', function () { + this.syncStub.returns(['path/file.json']) + + Runner.create({sync: this.syncStub}).assertion('**/*.json') + + expect(this.matchCreateStub.firstCall.firstArg).to.be.eql('path/file.json') + expect(this.syncStub.firstCall.firstArg).to.be.eql('**/*.json') + }) +}) From 1c34ef239558f8d4106fbbfdfd9b8c31f1a12eb8 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Tue, 5 Mar 2024 10:52:40 +0100 Subject: [PATCH 30/47] Update packages/sui-lint/bin/sui-lint-js.js Co-authored-by: Kiko Ruiz Lloret --- packages/sui-lint/bin/sui-lint-js.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index 91a826d04..65aca8901 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -14,7 +14,7 @@ program .option('--fix', 'fix automatically problems with js files') .option('--ignore-patterns ', 'Path patterns to ignore for linting') .option('--reporter ', 'Send results to DD using sui-logger') - .option('--pattern ', 'Patter of files to lint') + .option('--pattern ', 'Pattern of files to lint') .parse(process.argv) const {addFixes, fix, ignorePatterns = [], staged, pattern, reporter} = program.opts() From ab16dc574dd55c05ba032fd6db2b2b327cb00767 Mon Sep 17 00:00:00 2001 From: Kiko Ruiz Lloret Date: Tue, 5 Mar 2024 13:12:36 +0100 Subject: [PATCH 31/47] feat(packages/lint-repository-sui): add typescript lint repository rule --- packages/lint-repository-sui/src/index.js | 4 +- .../src/rules/typescript.js | 80 +++++++++++++++++++ .../test/server/typescriptSpec.js | 49 ++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 packages/lint-repository-sui/src/rules/typescript.js create mode 100644 packages/lint-repository-sui/test/server/typescriptSpec.js diff --git a/packages/lint-repository-sui/src/index.js b/packages/lint-repository-sui/src/index.js index 3ec72031b..d1f8a51d1 100644 --- a/packages/lint-repository-sui/src/index.js +++ b/packages/lint-repository-sui/src/index.js @@ -2,6 +2,7 @@ const NodeVersion = require('./rules/node-version.js') const ReactVersion = require('./rules/react-version.js') const PackageLock = require('./rules/package-lock.js') const GithubAction = require('./rules/github-action.js') +const TypeScript = require('./rules/typescript.js') // ------------------------------------------------------------------------------ // Plugin Definition @@ -13,6 +14,7 @@ module.exports = { 'node-version': NodeVersion, 'react-version': ReactVersion, 'package-lock': PackageLock, - 'github-action': GithubAction + 'github-action': GithubAction, + typescript: TypeScript } } diff --git a/packages/lint-repository-sui/src/rules/typescript.js b/packages/lint-repository-sui/src/rules/typescript.js new file mode 100644 index 000000000..a2a4dba4e --- /dev/null +++ b/packages/lint-repository-sui/src/rules/typescript.js @@ -0,0 +1,80 @@ +const dedent = require('string-dedent') + +const MIN_TYPESCRIPT_VERSION = 5 + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Check that your repository has a `tsconfig.json` file', + recommended: true, + url: null + }, + fixable: null, + schema: [], + messages: { + missingTypescriptDependency: dedent` + Your project doesn't have installed TypeScript. + Please install at least the version ${MIN_TYPESCRIPT_VERSION}. + If you are not sure about it, please contact Web Platform. + `, + badTypescriptVersion: dedent` + Please be sure that your repository use the latest TypeScript version ${MIN_TYPESCRIPT_VERSION}. + Your current version is {{version}}. + If you are not sure about it, please contact Web Platform. + `, + noTSConfigFile: dedent` + Every project must have a \`tsconfig.json\` file to setup TypeScript in the project. + If you are not sure about how do it, please contact with Web Platform team. + ` + } + }, + create: function (context) { + return { + 'tsconfig.json': () => { + // TO-DO: Check TypeScript configuration is the one we expect. + + return context.monitoring(true) + }, + 'package-lock.json': matches => { + const [packageLock] = matches + let version = packageLock?.parsed?.packages?.['node_modules/typescript']?.version + + // Check if repository is defining TS as dependency. + if (!version) { + context.report({ + messageId: 'missingTypescriptDependency' + }) + + return context.monitoring(false) + } + + version = version.split('.')[0] + + // Check if repository is using minimum expected version. + if (Number.parseInt(version) < MIN_TYPESCRIPT_VERSION) { + context.report({ + messageId: 'badTypescriptVersion', + data: {version} + }) + + return context.monitoring(false) + } + + return context.monitoring(true) + }, + missmatch: () => { + context.report({ + messageId: 'noTSConfigFile' + }) + + return context.monitoring(false) + } + } + }, + reduceMonitoring: function (monitorings) { + return monitorings.reduce((acc, signal) => { + return acc && signal.value + }, true) + } +} diff --git a/packages/lint-repository-sui/test/server/typescriptSpec.js b/packages/lint-repository-sui/test/server/typescriptSpec.js new file mode 100644 index 000000000..41d63d86b --- /dev/null +++ b/packages/lint-repository-sui/test/server/typescriptSpec.js @@ -0,0 +1,49 @@ +import dedent from 'dedent' + +import handler from '../../src/rules/typescript.js' +import {MatchStub, RuleTester} from '../TestHelpers.js' + +RuleTester.create('typescript', handler).run({ + valid: [ + { + 'tsconfig.json': [], + name: 'File `tsconfig.json` exists', + monitoring: true + }, + { + 'package-lock.json': [MatchStub.create({parsed: {packages: {'node_modules/typescript': {version: '5.0.4'}}}})], + name: 'TypeScript version is correct', + monitoring: true + } + ], + invalid: [ + { + 'package-lock.json': [MatchStub.create({parsed: {packages: {'node_modules/typescript': {version: '4.2.0'}}}})], + name: 'TypeScript version is not correct', + report: dedent` + Please be sure that your repository use the latest TypeScript version 5. + Your current version is 4. + If you are not sure about it, please contact Web Platform. + `, + monitoring: false + }, + { + 'package-lock.json': [MatchStub.create({parsed: {packages: {}}})], + name: 'TypeScript dependency is not installed', + report: dedent` + Your project doesn't have installed TypeScript. + Please install at least the version 5. + If you are not sure about it, please contact Web Platform. + `, + monitoring: false + }, + { + missmatch: '', + report: dedent` + Every project must have a \`tsconfig.json\` file to setup TypeScript in the project. + If you are not sure about how do it, please contact with Web Platform team. + `, + monitoring: false + } + ] +}) From 508fd8493180bbd6bab63e710e47fd2a6396f166 Mon Sep 17 00:00:00 2001 From: Kiko Ruiz Lloret Date: Tue, 5 Mar 2024 13:12:43 +0100 Subject: [PATCH 32/47] feat(packages/sui-lint): add typescript lint repository rule --- packages/sui-lint/package.json | 4 ++-- packages/sui-lint/repository.config.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/sui-lint/package.json b/packages/sui-lint/package.json index 9f4181b1e..32926f790 100644 --- a/packages/sui-lint/package.json +++ b/packages/sui-lint/package.json @@ -39,8 +39,8 @@ "eslint-plugin-react": "7.30.1", "eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-simple-import-sort": "7.0.0", - "eslint-plugin-sui": "beta", - "lint-repository-sui": "beta", + "eslint-plugin-sui": "../eslint-plugin-sui", + "lint-repository-sui": "../lint-repository-sui", "postcss-scss": "4.0.4", "prettier": "2.7.1", "stylelint": "14.11.0", diff --git a/packages/sui-lint/repository.config.js b/packages/sui-lint/repository.config.js index a4f0bf935..bd8ef0308 100644 --- a/packages/sui-lint/repository.config.js +++ b/packages/sui-lint/repository.config.js @@ -10,6 +10,7 @@ module.exports = { 'sui/node-version': RULES.WARNING, 'sui/react-version': RULES.WARNING, 'sui/package-lock': RULES.WARNING, - 'sui/github-action': RULES.WARNING + 'sui/github-action': RULES.WARNING, + 'sui/typescript': RULES.WARNING } } From 17c5f5e792dcefeae3a24b5e4c6da827d267b9ce Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Tue, 5 Mar 2024 14:56:08 +0100 Subject: [PATCH 33/47] refactor(packages/eslint-plugin-sui): avoid magic string add url to aggrements --- packages/eslint-plugin-sui/package.json | 10 ++++------ .../eslint-plugin-sui/src/rules/factory-pattern.js | 2 +- .../eslint-plugin-sui/src/rules/forbidden-require.js | 2 +- .../src/rules/function-named-parameters.js | 2 +- .../eslint-plugin-sui/src/rules/naming-convention.js | 2 +- .../src/rules/serialize-deserialize.js | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/eslint-plugin-sui/package.json b/packages/eslint-plugin-sui/package.json index bb67458ac..4bab4403e 100644 --- a/packages/eslint-plugin-sui/package.json +++ b/packages/eslint-plugin-sui/package.json @@ -18,17 +18,15 @@ "update:eslint-docs": "eslint-doc-generator" }, "dependencies": { - "requireindex": "^1.2.0", - "string-dedent": "^3.0.1" + "requireindex": "1.2.0", + "string-dedent": "3.0.1" }, "devDependencies": { - "@s-ui/test": "^8.33.0", + "@s-ui/test": "8", "eslint": "^8.19.0", "eslint-doc-generator": "^1.0.0", "eslint-plugin-eslint-plugin": "^5.0.0", - "eslint-plugin-node": "^11.1.0", - "mocha": "^10.0.0", - "npm-run-all": "^4.1.5" + "eslint-plugin-node": "^11.1.0" }, "engines": { "node": "^14.17.0 || ^16.0.0 || >= 18.0.0" diff --git a/packages/eslint-plugin-sui/src/rules/factory-pattern.js b/packages/eslint-plugin-sui/src/rules/factory-pattern.js index 97cf15290..23a13c446 100644 --- a/packages/eslint-plugin-sui/src/rules/factory-pattern.js +++ b/packages/eslint-plugin-sui/src/rules/factory-pattern.js @@ -17,7 +17,7 @@ module.exports = { docs: { description: 'ensure to define at least one factory function', recommended: true, - url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements/02-project-structure.md' + url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements' }, fixable: null, schema: [], diff --git a/packages/eslint-plugin-sui/src/rules/forbidden-require.js b/packages/eslint-plugin-sui/src/rules/forbidden-require.js index ec3dbe74e..5e31b845b 100644 --- a/packages/eslint-plugin-sui/src/rules/forbidden-require.js +++ b/packages/eslint-plugin-sui/src/rules/forbidden-require.js @@ -17,7 +17,7 @@ module.exports = { docs: { description: 'ensure to use only ESM (import) style', recommended: true, - url: null + url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements' }, fixable: null, schema: [], diff --git a/packages/eslint-plugin-sui/src/rules/function-named-parameters.js b/packages/eslint-plugin-sui/src/rules/function-named-parameters.js index d7fcd975a..e4327df59 100644 --- a/packages/eslint-plugin-sui/src/rules/function-named-parameters.js +++ b/packages/eslint-plugin-sui/src/rules/function-named-parameters.js @@ -17,7 +17,7 @@ module.exports = { docs: { description: 'ensure to use named parameters', recommended: true, - url: null + url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements' }, fixable: null, schema: [], diff --git a/packages/eslint-plugin-sui/src/rules/naming-convention.js b/packages/eslint-plugin-sui/src/rules/naming-convention.js index 68477031f..7da81c742 100644 --- a/packages/eslint-plugin-sui/src/rules/naming-convention.js +++ b/packages/eslint-plugin-sui/src/rules/naming-convention.js @@ -17,7 +17,7 @@ module.exports = { docs: { description: 'ensure to use a proper naming convention', recommended: true, - url: null + url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements' }, fixable: null, schema: [], diff --git a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js index 82232e19a..0a62ac3be 100644 --- a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js +++ b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js @@ -16,7 +16,7 @@ module.exports = { docs: { description: 'ensure entity create - toJSON', recommended: false, - url: null + url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements' }, fixable: null, schema: [], From 9d51b66cf99ecbfefa8861920a3ec23a0446cb22 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Tue, 5 Mar 2024 14:57:56 +0100 Subject: [PATCH 34/47] feat(packages/lint-repository-sui): Avoid magic strings --- packages/lint-repository-sui/package.json | 2 +- packages/lint-repository-sui/src/rules/node-version.js | 6 ++++-- packages/lint-repository-sui/src/rules/react-version.js | 8 +++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/lint-repository-sui/package.json b/packages/lint-repository-sui/package.json index 46455cfa6..8bbd986c7 100644 --- a/packages/lint-repository-sui/package.json +++ b/packages/lint-repository-sui/package.json @@ -10,6 +10,6 @@ "test": "npx sui-test server" }, "devDependencies": { - "@s-ui/test": "^8.33.0" + "@s-ui/test": "8" } } diff --git a/packages/lint-repository-sui/src/rules/node-version.js b/packages/lint-repository-sui/src/rules/node-version.js index 0e53b0f68..802bc7f80 100644 --- a/packages/lint-repository-sui/src/rules/node-version.js +++ b/packages/lint-repository-sui/src/rules/node-version.js @@ -1,5 +1,7 @@ const dedent = require('string-dedent') +const REACT_VERSION = '20' + module.exports = { meta: { type: 'problem', @@ -18,7 +20,7 @@ module.exports = { `, badNodeVersion: dedent` Your current Node version is {{version}}. - Please be sure that your repository use the latest Node Version 20. + Please be sure that your repository use the latest Node Version ${REACT_VERSION}. If you are not sure about how do it, please contact with Platform Web. `, noNMVRCFile: dedent` @@ -39,7 +41,7 @@ module.exports = { const [nvmrcMatch] = matches const version = nvmrcMatch.raw.trim() - if (version !== '20') { + if (version !== REACT_VERSION) { context.report({ messageId: 'badNodeVersion', data: {version} diff --git a/packages/lint-repository-sui/src/rules/react-version.js b/packages/lint-repository-sui/src/rules/react-version.js index 38411eb7f..acca08e0c 100644 --- a/packages/lint-repository-sui/src/rules/react-version.js +++ b/packages/lint-repository-sui/src/rules/react-version.js @@ -1,5 +1,7 @@ const dedent = require('string-dedent') +const REACT_VERSION = '18' + module.exports = { meta: { type: 'problem', @@ -12,13 +14,13 @@ module.exports = { schema: [], messages: { badReactVersion: dedent` - Please be sure that your repository use the latest React Version 18. + Please be sure that your repository use the latest React Version ${REACT_VERSION}. Your current version is {{version}}. If you are not sure about how do it, please contact with Platform Web. `, missingReactDependencie: dedent` Your project doesnt have installed React. - Please install at least the version 18. + Please install at least the version ${REACT_VERSION}. If you are not sure about how do it, please contact with Platform Web. `, missingPackageLock: dedent` @@ -42,7 +44,7 @@ module.exports = { version = version.split('.')[0] - if (version !== '18') { + if (version !== REACT_VERSION) { context.report({ messageId: 'badReactVersion', data: {version} From de098d69d5cfa0bf3e26bd4eaac21b4ed9d25902 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Tue, 5 Mar 2024 14:58:30 +0100 Subject: [PATCH 35/47] refactor(packages/sui-lint): refactor copies --- packages/sui-lint/bin/sui-lint-js.js | 3 ++- packages/sui-lint/src/RepositoryLinter/Results.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index 65aca8901..e4445b543 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -13,7 +13,7 @@ program .option('--staged') .option('--fix', 'fix automatically problems with js files') .option('--ignore-patterns ', 'Path patterns to ignore for linting') - .option('--reporter ', 'Send results to DD using sui-logger') + .option('--reporter ', 'Send results using a custom reporter') .option('--pattern ', 'Pattern of files to lint') .parse(process.argv) @@ -58,6 +58,7 @@ const baseConfig = { const {JSReporter} = await import(reporter) const reportered = await JSReporter.create() await reportered.map(results).send() + console.log('[sui-lint] All your stats has been sent', reporter) } if (fix) { diff --git a/packages/sui-lint/src/RepositoryLinter/Results.js b/packages/sui-lint/src/RepositoryLinter/Results.js index 6b837ca75..00de9d780 100644 --- a/packages/sui-lint/src/RepositoryLinter/Results.js +++ b/packages/sui-lint/src/RepositoryLinter/Results.js @@ -52,7 +52,7 @@ module.exports.Results = class Results { if (this.#monitorings.length === 0) return this.log(dedent` - There is not signal to be send to DD. Use 'context.monitoring' to add signals at your execution + There is not signal to be send. Use 'context.monitoring' to add signals at your execution `) From 369b096faf6ff77791d41eac9b136ff68ff814b8 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Fri, 8 Mar 2024 12:03:25 +0100 Subject: [PATCH 36/47] feat(packages/eslint-plugin-sui): Improve rules to be more resilient --- packages/eslint-plugin-sui/package.json | 10 ++-- .../src/rules/factory-pattern.js | 4 +- .../src/rules/serialize-deserialize.js | 22 ++++++-- .../test/server/factory-pattern.js | 53 ++++++++++++++++++- .../test/server/serialize-deserialize.js | 23 +++++++- 5 files changed, 97 insertions(+), 15 deletions(-) diff --git a/packages/eslint-plugin-sui/package.json b/packages/eslint-plugin-sui/package.json index 4bab4403e..0bfb0bedb 100644 --- a/packages/eslint-plugin-sui/package.json +++ b/packages/eslint-plugin-sui/package.json @@ -14,7 +14,7 @@ "lint": "npm-run-all \"lint:*\"", "lint:eslint-docs": "npm-run-all \"update:eslint-docs -- --check\"", "lint:js": "eslint .", - "test": "npx sui-test server -P ./tests/**/*.js", + "test": "npx sui-test server", "update:eslint-docs": "eslint-doc-generator" }, "dependencies": { @@ -23,10 +23,10 @@ }, "devDependencies": { "@s-ui/test": "8", - "eslint": "^8.19.0", - "eslint-doc-generator": "^1.0.0", - "eslint-plugin-eslint-plugin": "^5.0.0", - "eslint-plugin-node": "^11.1.0" + "eslint": "8.19.0", + "eslint-doc-generator": "1.0.0", + "eslint-plugin-eslint-plugin": "5.0.0", + "eslint-plugin-node": "11.1.0" }, "engines": { "node": "^14.17.0 || ^16.0.0 || >= 18.0.0" diff --git a/packages/eslint-plugin-sui/src/rules/factory-pattern.js b/packages/eslint-plugin-sui/src/rules/factory-pattern.js index 23a13c446..51168657b 100644 --- a/packages/eslint-plugin-sui/src/rules/factory-pattern.js +++ b/packages/eslint-plugin-sui/src/rules/factory-pattern.js @@ -48,14 +48,14 @@ module.exports = { node.body?.body?.find(methodDefinition => { return ( methodDefinition.static && - methodDefinition.value?.body?.body?.find(body => body.type === 'ReturnStatement')?.argument?.callee.name === node.id.name // eslint-disable-line + methodDefinition.value?.body?.body?.find?.(body => body.type === 'ReturnStatement')?.argument?.callee?.name === node?.id?.name // eslint-disable-line ) }) ) if (!hasStaticFactoryMethod) { context.report({ - node, + node: node?.id ?? node.superClass ?? node, messageId: 'notFoundFactoryFunction' }) } diff --git a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js index 0a62ac3be..c8faadbf8 100644 --- a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js +++ b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js @@ -30,6 +30,10 @@ module.exports = { missingCreateMethod: dedent` If your class has a 'toJSON' method. You have to define a 'static create' method too. The output of the 'toJSON' should be the same as the input of your 'static create' method + `, + forbiddenSpreadElements: dedent` + Spread operation are not allowed as part of the toJSON function. + The output of the 'toJSON' should be the same as the input of your 'static create' method ` } }, @@ -39,7 +43,7 @@ module.exports = { ClassDeclaration(node) { const create = node.body.body.find(i => i.key.name === 'create') const toJSON = node.body.body.find(i => i.key.name === 'toJSON') - const className = node.id.name + const className = node?.id?.name ?? '' if (['UseCase', 'Service', 'Repository'].some(allowWord => className.includes(allowWord))) return // eslint-disable-line @@ -47,13 +51,13 @@ module.exports = { if (create && !toJSON) return context.report({ - node: create, + node: create.key, messageId: 'missingToJSONMethod' }) if (toJSON && !create) return context.report({ - node: toJSON, + node: toJSON.key, messageId: 'missingCreateMethod' }) @@ -65,9 +69,17 @@ module.exports = { const createProperties = createParams.properties const toJSONProperties = toJSON.value.body.body[0].argument.properties + const spreadElement = toJSONProperties?.find(node => node.type === 'SpreadElement') + if(spreadElement) { + return context.report({ + node: spreadElement, + messageId: 'forbiddenSpreadElements' + }) + } + if (!toJSONProperties) { return context.report({ - node: toJSON, + node: toJSON.key, messageId: 'invalidTOJSONProperties' }) } @@ -78,7 +90,7 @@ module.exports = { const missingToJSONProps = createProps.filter(p => !toJSONProps.find(e => e === p)) if (missingToJSONProps.length) { context.report({ - node: toJSON, + node: toJSON.key, messageId: 'toJSONProperties', data: { props: missingToJSONProps.join(', ') diff --git a/packages/eslint-plugin-sui/test/server/factory-pattern.js b/packages/eslint-plugin-sui/test/server/factory-pattern.js index 2e63d949a..2adf1d6f6 100644 --- a/packages/eslint-plugin-sui/test/server/factory-pattern.js +++ b/packages/eslint-plugin-sui/test/server/factory-pattern.js @@ -8,7 +8,7 @@ import rule from '../../src/rules/factory-pattern.js' // more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester // ------------------------------------------------------------------------------ -const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) +const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 2018, sourceType: 'module'}}) ruleTester.run('factory-pattern', rule, { valid: [ { @@ -33,7 +33,56 @@ ruleTester.run('factory-pattern', rule, { Avoid to use the 'new' keyword directly in your code. Use always a factory function `, - type: 'ClassDeclaration' + } + ] + }, + { + code: dedent` + class Config { + static create() { + return {API_URL: 'google.com'} + } + } + `, + errors: [ + { + message: dedent` + You have to define at least one static function that return an instance of your class. + Avoid to use the 'new' keyword directly in your code. + Use always a factory function + `, + } + ] + }, + { + code: dedent` + class Config { + static create() { + return () => {} + } + } + `, + errors: [ + { + message: dedent` + You have to define at least one static function that return an instance of your class. + Avoid to use the 'new' keyword directly in your code. + Use always a factory function + `, + } + ] + }, + { + code: dedent` + export default class extends Model {} + `, + errors: [ + { + message: dedent` + You have to define at least one static function that return an instance of your class. + Avoid to use the 'new' keyword directly in your code. + Use always a factory function + `, } ] } diff --git a/packages/eslint-plugin-sui/test/server/serialize-deserialize.js b/packages/eslint-plugin-sui/test/server/serialize-deserialize.js index e5fd6d925..ea8ea49b5 100644 --- a/packages/eslint-plugin-sui/test/server/serialize-deserialize.js +++ b/packages/eslint-plugin-sui/test/server/serialize-deserialize.js @@ -8,7 +8,7 @@ import rule from '../../src/rules/serialize-deserialize.js' // more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester // ------------------------------------------------------------------------------ -const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 6}}) +const ruleTester = new RuleTester({parserOptions: {ecmaVersion: 2018}}) ruleTester.run('serialize-deserialize', rule, { valid: [ { @@ -91,6 +91,27 @@ ruleTester.run('serialize-deserialize', rule, { } `, errors: [{message: 'Missing toJSON properties (id, name)'}] + }, + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + return { + Noid: this.id, + ...this.user.toJSON() + } + } + } + `, + errors: [{message: dedent` + Spread operation are not allowed as part of the toJSON function. + The output of the 'toJSON' should be the same as the input of your 'static create' method + `}] } ] }) From 164ddf24f3bf05010c8f125f2e97f25031667a6f Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Fri, 8 Mar 2024 12:04:31 +0100 Subject: [PATCH 37/47] feat(packages/lint-repository-sui): Use only the major version of Node --- packages/lint-repository-sui/src/rules/node-version.js | 8 ++++---- .../lint-repository-sui/test/server/node-versionSpec.js | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/lint-repository-sui/src/rules/node-version.js b/packages/lint-repository-sui/src/rules/node-version.js index 802bc7f80..5b15ebbda 100644 --- a/packages/lint-repository-sui/src/rules/node-version.js +++ b/packages/lint-repository-sui/src/rules/node-version.js @@ -1,6 +1,6 @@ const dedent = require('string-dedent') -const REACT_VERSION = '20' +const NODE_VERSION = '20' module.exports = { meta: { @@ -20,7 +20,7 @@ module.exports = { `, badNodeVersion: dedent` Your current Node version is {{version}}. - Please be sure that your repository use the latest Node Version ${REACT_VERSION}. + Please be sure that your repository use the latest Node Version ${NODE_VERSION}. If you are not sure about how do it, please contact with Platform Web. `, noNMVRCFile: dedent` @@ -40,8 +40,8 @@ module.exports = { } const [nvmrcMatch] = matches - const version = nvmrcMatch.raw.trim() - if (version !== REACT_VERSION) { + const [version] = nvmrcMatch.raw.trim().split('.') + if (version !== NODE_VERSION) { context.report({ messageId: 'badNodeVersion', data: {version} diff --git a/packages/lint-repository-sui/test/server/node-versionSpec.js b/packages/lint-repository-sui/test/server/node-versionSpec.js index c113232b9..7314dd4e0 100644 --- a/packages/lint-repository-sui/test/server/node-versionSpec.js +++ b/packages/lint-repository-sui/test/server/node-versionSpec.js @@ -3,6 +3,8 @@ import dedent from 'dedent' import handler from '../../src/rules/node-version.js' import {MatchStub, RuleTester} from '../TestHelpers.js' + + RuleTester.create('node-version', handler).run({ valid: [ { @@ -23,7 +25,7 @@ RuleTester.create('node-version', handler).run({ monitoring: 0 }, { - '.nvmrc': [MatchStub.create({raw: '16'})], + '.nvmrc': [MatchStub.create({raw: '16.1.3'})], name: 'Exits more than one nvmrc file', report: dedent` Your current Node version is 16. From c42244c87d7e38392458751c1bfea9dbfa5e2809 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Fri, 8 Mar 2024 12:06:08 +0100 Subject: [PATCH 38/47] feat(packages/sui-lint): Allow relative path in reporter flag and select TS or JS eslint config --- packages/sui-lint/bin/sui-lint-js.js | 8 +- packages/sui-lint/bin/sui-lint-repository.js | 6 +- .../sui-lint/{eslintrc.js => eslintrc.js.js} | 10 +- packages/sui-lint/eslintrc.ts.js | 231 ++++++++++++++++++ packages/sui-lint/package.json | 4 +- 5 files changed, 249 insertions(+), 10 deletions(-) rename packages/sui-lint/{eslintrc.js => eslintrc.js.js} (97%) create mode 100644 packages/sui-lint/eslintrc.ts.js diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index e4445b543..55b884dc2 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -2,11 +2,13 @@ /* eslint-disable no-console */ // @ts-check +const path = require('path') +const fs = require("fs") const program = require('commander') const {checkFilesToLint, getFilesToLint, getGitIgnoredFiles, stageFilesIfRequired} = require('../src/helpers.js') const {ESLint} = require('eslint') -const config = require('../eslintrc.js') +const config = fs.existsSync(process.cwd() + '/tsconfig.json') ? require('../eslintrc.ts') : require('../eslintrc.js') program .option('--add-fixes') @@ -55,7 +57,9 @@ const baseConfig = { if (reporter) { console.log('[sui-lint] Sending stats using the reporter ', reporter) - const {JSReporter} = await import(reporter) + const reporterPath = path.isAbsolute(reporter) ? reporter : path.join(process.cwd() + '/' + reporter) + console.log({reporter, isAbsolute: path.isAbsolute(reporter), reporterPath}) + const {JSReporter} = await import(reporterPath) const reportered = await JSReporter.create() await reportered.map(results).send() console.log('[sui-lint] All your stats has been sent', reporter) diff --git a/packages/sui-lint/bin/sui-lint-repository.js b/packages/sui-lint/bin/sui-lint-repository.js index e8d845225..86f96d144 100755 --- a/packages/sui-lint/bin/sui-lint-repository.js +++ b/packages/sui-lint/bin/sui-lint-repository.js @@ -1,5 +1,6 @@ #!/usr/bin/env node /* eslint-disable no-console */ +const path = require('path') const program = require('commander') const {RepositoryLinter} = require('../src/RepositoryLinter') @@ -25,7 +26,10 @@ const {reporter, outputJson} = program.opts() if (reporter) { console.log('\n[sui-lint] Sending stats using the reporter\n\n', reporter) - const {RepositoryReporter} = await import(reporter) + const reporterPath = path.isAbsolute(reporter) ? reporter : path.join(process.cwd() + '/' + reporter) + console.log({reporter, isAbsolute: path.isAbsolute(reporter), reporterPath}) + const {RepositoryReporter} = await import(reporterPath) + const reportered = RepositoryReporter.create() await reportered.map(results).send() results.logMonitorings() diff --git a/packages/sui-lint/eslintrc.js b/packages/sui-lint/eslintrc.js.js similarity index 97% rename from packages/sui-lint/eslintrc.js rename to packages/sui-lint/eslintrc.js.js index 7f089f0e2..5eeb20833 100644 --- a/packages/sui-lint/eslintrc.js +++ b/packages/sui-lint/eslintrc.js.js @@ -175,8 +175,8 @@ module.exports = { 'react-hooks', 'simple-import-sort', 'jest', - 'jest-dom' - // 'sui' + 'jest-dom', + 'sui' ], rules: { ...REACT_RULES, @@ -199,9 +199,9 @@ module.exports = { 'prefer-regex-literals': RULES.WARNING, 'prettier/prettier': [RULES.ERROR, prettierOptions], 'simple-import-sort/imports': [RULES.WARNING, {groups: IMPORT_SORT_GROUPS}], - 'react/jsx-no-bind': RULES.OFF - // 'sui/factory-pattern': RULES.ERROR, - // 'sui/serialize-deserialize': RULES.ERROR + 'react/jsx-no-bind': RULES.OFF, + 'sui/factory-pattern': RULES.WARNING, + 'sui/serialize-deserialize': RULES.WARNING }, overrides: [ { diff --git a/packages/sui-lint/eslintrc.ts.js b/packages/sui-lint/eslintrc.ts.js new file mode 100644 index 000000000..9f4b2658e --- /dev/null +++ b/packages/sui-lint/eslintrc.ts.js @@ -0,0 +1,231 @@ +const prettierOptions = require('./.prettierrc.js') + +const RULES = { + OFF: 0, + WARNING: 1, + ERROR: 2 +} + +const REACT_RULES = { + 'react-hooks/exhaustive-deps': RULES.WARNING, // Checks effect dependencies + 'react-hooks/rules-of-hooks': RULES.ERROR, // Checks rules of Hooks + 'react/default-props-match-prop-types': RULES.WARNING, + 'react/jsx-handler-names': RULES.WARNING, + 'react/jsx-no-bind': RULES.WARNING, + 'react/jsx-no-duplicate-props': [RULES.WARNING, {ignoreCase: true}], + 'react/jsx-no-undef': RULES.WARNING, + 'react/jsx-pascal-case': [ + RULES.WARNING, + { + allowAllCaps: true, + ignore: [] + } + ], + 'react/jsx-uses-react': RULES.OFF, + 'react/jsx-uses-vars': RULES.WARNING, + 'react/no-deprecated': RULES.WARNING, + 'react/no-did-update-set-state': RULES.ERROR, + 'react/no-direct-mutation-state': RULES.ERROR, + 'react/no-is-mounted': RULES.WARNING, + 'react/no-multi-comp': [RULES.WARNING, {ignoreStateless: true}], + 'react/no-unused-prop-types': RULES.WARNING, + 'react/no-unknown-property': RULES.ERROR, + 'react/prop-types': RULES.ERROR, + 'react/react-in-jsx-scope': RULES.OFF, + 'react/require-render-return': RULES.WARNING, + 'react/no-unstable-nested-components': RULES.WARNING +} + +const TESTING_RULES = { + 'chai-friendly/no-unused-expressions': [RULES.ERROR, {allowShortCircuit: true, allowTernary: true}], + 'no-only-tests/no-only-tests': RULES.ERROR +} + +const JEST_TESTING_RULES = { + 'react/display-name': RULES.OFF, + 'jest/consistent-test-it': RULES.OFF, + 'jest/expect-expect': RULES.OFF, + 'jest/max-expects': RULES.OFF, + 'jest/max-nested-describe': RULES.ERROR, + 'jest/no-alias-methods': RULES.OFF, + 'jest/no-commented-out-tests': RULES.WARNING, + 'jest/no-conditional-expect': RULES.ERROR, + 'jest/no-conditional-in-test': RULES.ERROR, + 'jest/no-deprecated-functions': RULES.ERROR, + 'jest/no-disabled-tests': RULES.WARNING, + 'jest/no-done-callback': RULES.ERROR, + 'jest/no-duplicate-hooks': RULES.OFF, + 'jest/no-export': RULES.ERROR, + 'jest/no-focused-tests': RULES.ERROR, + 'jest/no-hooks': RULES.OFF, + 'jest/no-identical-title': RULES.ERROR, + 'jest/no-if': RULES.ERROR, + 'jest/no-interpolation-in-snapshots': RULES.ERROR, + 'jest/no-jasmine-globals': RULES.OFF, + 'jest/no-large-snapshots': [RULES.WARNING, {maxSize: 300}], + 'jest/no-mocks-import': RULES.ERROR, + 'jest/no-restricted-matchers': RULES.OFF, + 'jest/no-standalone-expect': RULES.OFF, + 'jest/no-test-prefixes': RULES.ERROR, + 'jest/no-test-return-statement': RULES.OFF, + 'jest/prefer-called-with': RULES.ERROR, + 'jest/prefer-comparison-matcher': RULES.ERROR, + 'jest/prefer-each': RULES.ERROR, + 'jest/prefer-equality-matcher': RULES.ERROR, + 'jest/prefer-expect-assertions': RULES.OFF, + 'jest/prefer-expect-resolves': RULES.OFF, + 'jest/prefer-hooks-in-order': RULES.ERROR, + 'jest/prefer-hooks-on-top': RULES.ERROR, + 'jest/prefer-lowercase-title': RULES.OFF, + 'jest/prefer-mock-promise-shorthand': RULES.ERROR, + 'jest/prefer-snapshot-hint': RULES.ERROR, + 'jest/prefer-spy-on': RULES.OFF, + 'jest/prefer-strict-equal': RULES.OFF, + 'jest/prefer-to-be': RULES.OFF, + 'jest/prefer-to-contain': RULES.WARNING, + 'jest/prefer-to-have-length': RULES.WARNING, + 'jest/prefer-todo': RULES.WARNING, + 'jest/require-hook': RULES.OFF, + 'jest/require-to-throw-message': RULES.OFF, + 'jest/require-top-level-describe': RULES.OFF, + 'jest/unbound-method': RULES.OFF, + 'jest/valid-describe-callback': RULES.ERROR, + 'jest/valid-expect': RULES.ERROR, + 'jest/valid-expect-in-promise': RULES.ERROR, + 'jest/valid-title': RULES.WARNING, + 'jest-dom/prefer-checked': RULES.ERROR, + 'jest-dom/prefer-empty': RULES.ERROR, + 'jest-dom/prefer-enabled-disabled': RULES.ERROR, + 'jest-dom/prefer-focus': RULES.ERROR, + 'jest-dom/prefer-in-document': RULES.ERROR, + 'jest-dom/prefer-required': RULES.ERROR, + 'jest-dom/prefer-to-have-attribute': RULES.ERROR, + 'jest-dom/prefer-to-have-class': RULES.ERROR, + 'jest-dom/prefer-to-have-style': RULES.ERROR, + 'jest-dom/prefer-to-have-text-content': RULES.ERROR, + 'jest-dom/prefer-to-have-value': RULES.ERROR +} + +const IMPORT_SORT_GROUPS = [ + // Side effect and polyfill imports. + ['^\\u0000'], + // Built-in node dependencies + [ + '^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)' + ], + // Packages. `react` related packages come first. + ['^react'], + // Standalone packages. + ['^\\w'], + // Generic organization packages. + ['^@'], + // S-UI & ADV-UI organization packages. + ['^@s-ui', '^@adv-ui'], + // Relative imports. Put `./` last. + ['^\\.\\.(?!/?$)', '^\\.\\./?$', '^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'], + // Style imports. + ['^.+\\.s?css$'] +] + +let resolvedBabelPresetSui +try { + resolvedBabelPresetSui = require.resolve('babel-preset-sui') +} catch {} + +const parser = resolvedBabelPresetSui ? '@babel/eslint-parser' : undefined + +module.exports = { + parser, + + env: { + es6: true, + mocha: true, + 'jest/globals': true + }, + + globals: { + 'cypress/globals': true, + preval: 'readonly' + }, + + parserOptions: { + ecmaFeatures: { + jsx: true + }, + ecmaVersion: 12, + babelOptions: { + configFile: resolvedBabelPresetSui + } + }, + + settings: { + react: { + version: 'detect' + } + }, + + extends: ['standard', 'plugin:cypress/recommended', 'prettier'], + + plugins: [ + '@babel', + 'chai-friendly', + 'no-only-tests', + 'prettier', + 'react', + 'react-hooks', + 'simple-import-sort', + 'jest', + 'jest-dom', + 'sui' + ], + rules: { + ...REACT_RULES, + ...TESTING_RULES, + '@babel/no-unused-expressions': RULES.OFF, + 'accessor-pairs': RULES.OFF, + 'array-callback-return': RULES.WARNING, + 'import/no-webpack-loader-syntax': RULES.WARNING, + 'import/extensions': [RULES.WARNING, 'always', {ignorePackages: true}], + 'n/no-path-concat': RULES.WARNING, + 'no-console': RULES.WARNING, + 'no-debugger': RULES.ERROR, + 'no-nested-ternary': RULES.WARNING, + 'no-prototype-builtins': RULES.OFF, + 'no-return-await': RULES.WARNING, + 'no-unused-expressions': RULES.OFF, + 'no-unused-vars': [RULES.ERROR, {args: 'none', ignoreRestSiblings: true, varsIgnorePattern: 'React'}], + 'no-var': RULES.WARNING, + strict: RULES.OFF, + 'prefer-regex-literals': RULES.WARNING, + 'prettier/prettier': [RULES.ERROR, prettierOptions], + 'simple-import-sort/imports': [RULES.WARNING, {groups: IMPORT_SORT_GROUPS}], + 'react/jsx-no-bind': RULES.OFF, + 'sui/factory-pattern': RULES.WARNING, + 'sui/serialize-deserialize': RULES.WARNING + }, + overrides: [ + { + files: ['**/*.+(ts|tsx)'], + extends: ['standard-with-typescript', 'standard-react', 'prettier'], + parser: '@typescript-eslint/parser', + parserOptions: { + project: './tsconfig.json' + }, + rules: { + 'import/extensions': RULES.OFF, + 'no-return-await': RULES.OFF, + 'prettier/prettier': [RULES.ERROR, prettierOptions], + 'react/react-in-jsx-scope': RULES.OFF, + 'react/no-unused-prop-types': RULES.OFF, + '@typescript-eslint/explicit-function-return-type': [RULES.OFF, {allowTypedFunctionExpressions: false}], + 'chai-friendly/no-unused-expressions': RULES.ERROR, + '@typescript-eslint/no-unused-expressions': RULES.OFF, + '@typescript-eslint/return-await': RULES.OFF + } + }, + { + files: ['**/__tests__/**/*.js'], + rules: JEST_TESTING_RULES + } + ] +} diff --git a/packages/sui-lint/package.json b/packages/sui-lint/package.json index 32926f790..9f4181b1e 100644 --- a/packages/sui-lint/package.json +++ b/packages/sui-lint/package.json @@ -39,8 +39,8 @@ "eslint-plugin-react": "7.30.1", "eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-simple-import-sort": "7.0.0", - "eslint-plugin-sui": "../eslint-plugin-sui", - "lint-repository-sui": "../lint-repository-sui", + "eslint-plugin-sui": "beta", + "lint-repository-sui": "beta", "postcss-scss": "4.0.4", "prettier": "2.7.1", "stylelint": "14.11.0", From 48b4ef65b0d7d24adf934f9ca5ec54357f170047 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Fri, 8 Mar 2024 13:50:05 +0100 Subject: [PATCH 39/47] feat(packages/sui-lint): Add flag to force lint all files --- packages/sui-lint/bin/sui-lint-js.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index 55b884dc2..a5cce7a1c 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -13,13 +13,14 @@ const config = fs.existsSync(process.cwd() + '/tsconfig.json') ? require('../esl program .option('--add-fixes') .option('--staged') + .option('--force-full-lint', 'force to lint all the JS files') .option('--fix', 'fix automatically problems with js files') .option('--ignore-patterns ', 'Path patterns to ignore for linting') .option('--reporter ', 'Send results using a custom reporter') .option('--pattern ', 'Pattern of files to lint') .parse(process.argv) -const {addFixes, fix, ignorePatterns = [], staged, pattern, reporter} = program.opts() +const {addFixes, fix, ignorePatterns = [], staged, pattern, reporter, forceFullLint} = program.opts() const {CI} = process.env const EXTENSIONS = ['js', 'jsx', 'ts', 'tsx'] @@ -53,7 +54,11 @@ const baseConfig = { useEslintrc: false }) - const results = await eslint.lintFiles(files) + if (forceFullLint) { + console.log('[sui-lint] force to lint all our JS files') + } + + const results = await eslint.lintFiles(!forceFullLint ? files : DEFAULT_PATTERN) if (reporter) { console.log('[sui-lint] Sending stats using the reporter ', reporter) From 3865416ff0553fb36593a9cb138bd15c4cc29775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20Leo=CC=81n?= Date: Fri, 8 Mar 2024 13:51:07 +0100 Subject: [PATCH 40/47] feat(packages/eslint-plugin-sui): fix more than one line in toJson --- packages/eslint-plugin-sui/package.json | 2 +- .../src/rules/serialize-deserialize.js | 3 +- .../test/server/serialize-deserialize.js | 28 +++++++++++++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin-sui/package.json b/packages/eslint-plugin-sui/package.json index 0bfb0bedb..d33ba7133 100644 --- a/packages/eslint-plugin-sui/package.json +++ b/packages/eslint-plugin-sui/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-sui", - "version": "0.0.0", + "version": "1.0.0-beta.9", "description": "Set of sui lint rules", "keywords": [ "eslint", diff --git a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js index c8faadbf8..9d1bf68a9 100644 --- a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js +++ b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js @@ -67,7 +67,8 @@ module.exports = { } const createProperties = createParams.properties - const toJSONProperties = toJSON.value.body.body[0].argument.properties + const toJSONProperties = toJSON.value.body.body?.find(node => node.type === 'ReturnStatement')?.argument + ?.properties const spreadElement = toJSONProperties?.find(node => node.type === 'SpreadElement') if(spreadElement) { diff --git a/packages/eslint-plugin-sui/test/server/serialize-deserialize.js b/packages/eslint-plugin-sui/test/server/serialize-deserialize.js index ea8ea49b5..6ff0e8dbb 100644 --- a/packages/eslint-plugin-sui/test/server/serialize-deserialize.js +++ b/packages/eslint-plugin-sui/test/server/serialize-deserialize.js @@ -20,6 +20,26 @@ ruleTester.run('serialize-deserialize', rule, { this.name = name } toJSON() { + return { + id: this.id, + name: this.name + } + } + } + ` + }, + { + code: dedent` + class User { + static create({id, name}) { return new User(id, name) } + constructor(id, name) { + this.id = id + this.name = name + } + toJSON() { + const name="John" + const surname="Doe" + return { id: this.id, name: this.name @@ -108,10 +128,14 @@ ruleTester.run('serialize-deserialize', rule, { } } `, - errors: [{message: dedent` + errors: [ + { + message: dedent` Spread operation are not allowed as part of the toJSON function. The output of the 'toJSON' should be the same as the input of your 'static create' method - `}] + ` + } + ] } ] }) From 75d31c62190d715a9281f3be7e461251e877a440 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Thu, 14 Mar 2024 10:38:28 +0100 Subject: [PATCH 41/47] feat(packages/sui-lint): add new dependency --- packages/sui-lint/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/sui-lint/package.json b/packages/sui-lint/package.json index 9f4181b1e..fa6ab1976 100644 --- a/packages/sui-lint/package.json +++ b/packages/sui-lint/package.json @@ -21,11 +21,10 @@ "@typescript-eslint/eslint-plugin": "5.62.0", "commander": "8.3.0", "console-table-printer": "2.12.0", - "js-yaml": "4.1.0", - "fast-glob": "3.3.2", "eslint": "8.56.0", "eslint-config-prettier": "8.5.0", "eslint-config-standard": "17.0.0", + "eslint-config-standard-react": "^13.0.0", "eslint-config-standard-with-typescript": "22.0.0", "eslint-plugin-chai-friendly": "0.7.2", "eslint-plugin-cypress": "2.12.1", @@ -40,6 +39,8 @@ "eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-simple-import-sort": "7.0.0", "eslint-plugin-sui": "beta", + "fast-glob": "3.3.2", + "js-yaml": "4.1.0", "lint-repository-sui": "beta", "postcss-scss": "4.0.4", "prettier": "2.7.1", From 0324821fc9dc0d57dbdc78db86d587439650f85e Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Thu, 14 Mar 2024 11:09:16 +0100 Subject: [PATCH 42/47] feat(packages/sui-lint): add new dependency --- packages/lint-repository-sui/test/server/node-versionSpec.js | 2 -- packages/sui-lint/bin/sui-lint-js.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/lint-repository-sui/test/server/node-versionSpec.js b/packages/lint-repository-sui/test/server/node-versionSpec.js index 7314dd4e0..daf20325d 100644 --- a/packages/lint-repository-sui/test/server/node-versionSpec.js +++ b/packages/lint-repository-sui/test/server/node-versionSpec.js @@ -3,8 +3,6 @@ import dedent from 'dedent' import handler from '../../src/rules/node-version.js' import {MatchStub, RuleTester} from '../TestHelpers.js' - - RuleTester.create('node-version', handler).run({ valid: [ { diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index a5cce7a1c..7d2c6735c 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -3,7 +3,7 @@ // @ts-check const path = require('path') -const fs = require("fs") +const fs = require('fs') const program = require('commander') const {checkFilesToLint, getFilesToLint, getGitIgnoredFiles, stageFilesIfRequired} = require('../src/helpers.js') From 27c6e29eed1b33f2fb5a06cff53413717a88a856 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Thu, 14 Mar 2024 11:14:49 +0100 Subject: [PATCH 43/47] feat(packages/sui-lint): add new dependency --- .../eslint-plugin-sui/src/rules/serialize-deserialize.js | 2 +- packages/eslint-plugin-sui/test/server/factory-pattern.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js index 9d1bf68a9..33c6c2232 100644 --- a/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js +++ b/packages/eslint-plugin-sui/src/rules/serialize-deserialize.js @@ -71,7 +71,7 @@ module.exports = { ?.properties const spreadElement = toJSONProperties?.find(node => node.type === 'SpreadElement') - if(spreadElement) { + if (spreadElement) { return context.report({ node: spreadElement, messageId: 'forbiddenSpreadElements' diff --git a/packages/eslint-plugin-sui/test/server/factory-pattern.js b/packages/eslint-plugin-sui/test/server/factory-pattern.js index 2adf1d6f6..cbde9a821 100644 --- a/packages/eslint-plugin-sui/test/server/factory-pattern.js +++ b/packages/eslint-plugin-sui/test/server/factory-pattern.js @@ -32,7 +32,7 @@ ruleTester.run('factory-pattern', rule, { You have to define at least one static function that return an instance of your class. Avoid to use the 'new' keyword directly in your code. Use always a factory function - `, + ` } ] }, @@ -50,7 +50,7 @@ ruleTester.run('factory-pattern', rule, { You have to define at least one static function that return an instance of your class. Avoid to use the 'new' keyword directly in your code. Use always a factory function - `, + ` } ] }, @@ -68,7 +68,7 @@ ruleTester.run('factory-pattern', rule, { You have to define at least one static function that return an instance of your class. Avoid to use the 'new' keyword directly in your code. Use always a factory function - `, + ` } ] }, @@ -82,7 +82,7 @@ ruleTester.run('factory-pattern', rule, { You have to define at least one static function that return an instance of your class. Avoid to use the 'new' keyword directly in your code. Use always a factory function - `, + ` } ] } From b66fd7dfae0c3eeeecd6f1d034259defddd24090 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Thu, 14 Mar 2024 11:20:55 +0100 Subject: [PATCH 44/47] feat(packages/sui-lint): disable sui checks --- packages/sui-lint/eslintrc.js.js | 10 +++++----- packages/sui-lint/eslintrc.ts.js | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/sui-lint/eslintrc.js.js b/packages/sui-lint/eslintrc.js.js index 5eeb20833..3681f04a3 100644 --- a/packages/sui-lint/eslintrc.js.js +++ b/packages/sui-lint/eslintrc.js.js @@ -175,8 +175,8 @@ module.exports = { 'react-hooks', 'simple-import-sort', 'jest', - 'jest-dom', - 'sui' + 'jest-dom' + // 'sui' ], rules: { ...REACT_RULES, @@ -199,9 +199,9 @@ module.exports = { 'prefer-regex-literals': RULES.WARNING, 'prettier/prettier': [RULES.ERROR, prettierOptions], 'simple-import-sort/imports': [RULES.WARNING, {groups: IMPORT_SORT_GROUPS}], - 'react/jsx-no-bind': RULES.OFF, - 'sui/factory-pattern': RULES.WARNING, - 'sui/serialize-deserialize': RULES.WARNING + 'react/jsx-no-bind': RULES.OFF + // 'sui/factory-pattern': RULES.WARNING, + // 'sui/serialize-deserialize': RULES.WARNING }, overrides: [ { diff --git a/packages/sui-lint/eslintrc.ts.js b/packages/sui-lint/eslintrc.ts.js index 9f4b2658e..985ac0dda 100644 --- a/packages/sui-lint/eslintrc.ts.js +++ b/packages/sui-lint/eslintrc.ts.js @@ -175,8 +175,8 @@ module.exports = { 'react-hooks', 'simple-import-sort', 'jest', - 'jest-dom', - 'sui' + 'jest-dom' + // 'sui' ], rules: { ...REACT_RULES, @@ -199,9 +199,9 @@ module.exports = { 'prefer-regex-literals': RULES.WARNING, 'prettier/prettier': [RULES.ERROR, prettierOptions], 'simple-import-sort/imports': [RULES.WARNING, {groups: IMPORT_SORT_GROUPS}], - 'react/jsx-no-bind': RULES.OFF, - 'sui/factory-pattern': RULES.WARNING, - 'sui/serialize-deserialize': RULES.WARNING + 'react/jsx-no-bind': RULES.OFF + // 'sui/factory-pattern': RULES.WARNING, + // 'sui/serialize-deserialize': RULES.WARNING }, overrides: [ { From 57e55cfeba74087b2da535cadbe85e07190cdf8d Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Thu, 14 Mar 2024 11:42:29 +0100 Subject: [PATCH 45/47] feat(packages/sui-lint): disable sui checks --- package.json | 2 +- packages/sui-lint/bin/sui-lint-js.js | 2 +- packages/sui-lint/{eslintrc.js.js => eslintrc.js} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/sui-lint/{eslintrc.js.js => eslintrc.js} (100%) diff --git a/package.json b/package.json index f0951fa56..e41587415 100644 --- a/package.json +++ b/package.json @@ -79,4 +79,4 @@ "stylelint": { "extends": "./node_modules/@s-ui/lint/stylelint.config.js" } -} \ No newline at end of file +} diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index 7d2c6735c..cdef41c06 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -8,7 +8,7 @@ const program = require('commander') const {checkFilesToLint, getFilesToLint, getGitIgnoredFiles, stageFilesIfRequired} = require('../src/helpers.js') const {ESLint} = require('eslint') -const config = fs.existsSync(process.cwd() + '/tsconfig.json') ? require('../eslintrc.ts') : require('../eslintrc.js') +const config = fs.existsSync(process.cwd() + '/tsconfig.json') ? require('../eslintrc.ts.js') : require('../eslintrc.js') program .option('--add-fixes') diff --git a/packages/sui-lint/eslintrc.js.js b/packages/sui-lint/eslintrc.js similarity index 100% rename from packages/sui-lint/eslintrc.js.js rename to packages/sui-lint/eslintrc.js From 958cfc6b858eae5cfea94bc51f32fb6806531675 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Thu, 21 Mar 2024 12:18:48 +0100 Subject: [PATCH 46/47] feat(packages/sui-lint): fix lint --- packages/sui-lint/bin/sui-lint-js.js | 4 +++- packages/sui-lint/eslintrc.js | 11 ++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/sui-lint/bin/sui-lint-js.js b/packages/sui-lint/bin/sui-lint-js.js index cdef41c06..68bd23484 100755 --- a/packages/sui-lint/bin/sui-lint-js.js +++ b/packages/sui-lint/bin/sui-lint-js.js @@ -8,7 +8,9 @@ const program = require('commander') const {checkFilesToLint, getFilesToLint, getGitIgnoredFiles, stageFilesIfRequired} = require('../src/helpers.js') const {ESLint} = require('eslint') -const config = fs.existsSync(process.cwd() + '/tsconfig.json') ? require('../eslintrc.ts.js') : require('../eslintrc.js') +const config = fs.existsSync(process.cwd() + '/tsconfig.json') + ? require('../eslintrc.ts.js') + : require('../eslintrc.js') program .option('--add-fixes') diff --git a/packages/sui-lint/eslintrc.js b/packages/sui-lint/eslintrc.js index 3681f04a3..02ee6aa3c 100644 --- a/packages/sui-lint/eslintrc.js +++ b/packages/sui-lint/eslintrc.js @@ -176,7 +176,6 @@ module.exports = { 'simple-import-sort', 'jest', 'jest-dom' - // 'sui' ], rules: { ...REACT_RULES, @@ -200,10 +199,16 @@ module.exports = { 'prettier/prettier': [RULES.ERROR, prettierOptions], 'simple-import-sort/imports': [RULES.WARNING, {groups: IMPORT_SORT_GROUPS}], 'react/jsx-no-bind': RULES.OFF - // 'sui/factory-pattern': RULES.WARNING, - // 'sui/serialize-deserialize': RULES.WARNING }, overrides: [ + // { + // files: ['**/domain/src/**'], + // plugins: ['sui'], + // rules: { + // 'sui/factory-pattern': RULES.WARNING, + // 'sui/serialize-deserialize': RULES.WARNING + // } + // }, { files: ['**/*.+(ts|tsx)'], extends: ['standard-with-typescript'], From 19dfdd6f7cec7ff50f246864f3fe1e4e05a2d8d4 Mon Sep 17 00:00:00 2001 From: Carlos Villuendas Zambrana Date: Thu, 21 Mar 2024 12:37:55 +0100 Subject: [PATCH 47/47] chore(packages/eslint-plugin-sui): add npx --- packages/eslint-plugin-sui/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin-sui/package.json b/packages/eslint-plugin-sui/package.json index d33ba7133..e6f9ccb1b 100644 --- a/packages/eslint-plugin-sui/package.json +++ b/packages/eslint-plugin-sui/package.json @@ -11,11 +11,11 @@ "main": "./src/index.js", "exports": "./src/index.js", "scripts": { - "lint": "npm-run-all \"lint:*\"", - "lint:eslint-docs": "npm-run-all \"update:eslint-docs -- --check\"", - "lint:js": "eslint .", + "lint": "npx npm-run-all \"lint:*\"", + "lint:eslint-docs": "npx npm-run-all \"update:eslint-docs -- --check\"", + "lint:js": "npx eslint .", "test": "npx sui-test server", - "update:eslint-docs": "eslint-doc-generator" + "update:eslint-docs": "npx eslint-doc-generator" }, "dependencies": { "requireindex": "1.2.0",