diff --git a/packages/eslint-plugin-sui/CHANGELOG.md b/packages/eslint-plugin-sui/CHANGELOG.md index 17d7c7508..b6d4ef7a7 100644 --- a/packages/eslint-plugin-sui/CHANGELOG.md +++ b/packages/eslint-plugin-sui/CHANGELOG.md @@ -1,5 +1,16 @@ # CHANGELOG +# 1.4.0 (2024-04-30) + + +### Features + +* add basic decorators rules for UseCases ([86ef4a2](https://github.com/SUI-Components/sui/commit/86ef4a25ee642b6a1fe2cdb134958a342f13edcf)) +* Add rule to mark any uso off commonjs syntax in our code ([f210c46](https://github.com/SUI-Components/sui/commit/f210c46717117b4132a3586a2e2fe2548a4a51d2)) +* Allow require from ESM module ([ea666e0](https://github.com/SUI-Components/sui/commit/ea666e0495246e15d209aac2a8ad1acc477430a1)) + + + # 1.3.0 (2024-03-21) diff --git a/packages/eslint-plugin-sui/package.json b/packages/eslint-plugin-sui/package.json index bfb860bd7..05e122a4c 100644 --- a/packages/eslint-plugin-sui/package.json +++ b/packages/eslint-plugin-sui/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-sui", - "version": "1.3.0", + "version": "1.4.0", "access": "public", "description": "Set of sui lint rules", "keywords": [ diff --git a/packages/eslint-plugin-sui/src/index.js b/packages/eslint-plugin-sui/src/index.js index 84d25af60..3e33063fa 100644 --- a/packages/eslint-plugin-sui/src/index.js +++ b/packages/eslint-plugin-sui/src/index.js @@ -1,5 +1,7 @@ const FactoryPattern = require('./rules/factory-pattern.js') const SerializeDeserialize = require('./rules/serialize-deserialize.js') +const CommonJS = require('./rules/commonjs.js') +const Decorators = require('./rules/decorators.js') // ------------------------------------------------------------------------------ // Plugin Definition @@ -9,6 +11,8 @@ const SerializeDeserialize = require('./rules/serialize-deserialize.js') module.exports = { rules: { 'factory-pattern': FactoryPattern, - 'serialize-deserialize': SerializeDeserialize + 'serialize-deserialize': SerializeDeserialize, + commonjs: CommonJS, + decorators: Decorators } } diff --git a/packages/eslint-plugin-sui/src/rules/commonjs.js b/packages/eslint-plugin-sui/src/rules/commonjs.js new file mode 100644 index 000000000..88d6dacf0 --- /dev/null +++ b/packages/eslint-plugin-sui/src/rules/commonjs.js @@ -0,0 +1,118 @@ +/** + * @fileoverview Ensure your code is not using CommonJS signatures like module.exports or moduel.exports.foo or require() or require.resolve() + */ +'use strict' + +const dedent = require('string-dedent') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Ensure that your code is using ems over commonjs modules', + recommended: true, + url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements' + }, + fixable: null, + schema: [], + messages: { + forbiddenExports: dedent` + Use module.* should be avoid. + `, + forbiddenRequires: dedent` + Use require function should be avoid. + `, + forbiddenModuleRequire: dedent` + Use module.require function should be avoid. + `, + forbiddenRequiresObjects: dedent` + Use require.cache or require.extensions or require.main should be avoid. + `, + forbiddenRequireResolve: dedent` + Use require.resolve function should be avoid. + `, + forbidden__filename: dedent` + __filename should be avoid + `, + forbidden__dirname: dedent` + __dirname should be avoid + ` + } + }, + create: function (context) { + return { + CallExpression(node) { + const isRequire = node.callee?.name === 'require' + const isResolve = node.callee?.object?.name === 'require' && node.callee?.property?.name === 'resolve' + const isModule = node.callee?.object?.name === 'module' && node.callee?.property?.name === 'require' + + const isRequireFormCreateRequire = node.parent?.parent?.body + ?.filter(node => node.type === 'ImportDeclaration') + ?.some( + node => + node.source?.value === 'module' && node.specifiers?.some(spec => spec.imported?.name === 'createRequire') + ) + + isRequire && + !isRequireFormCreateRequire && + context.report({ + node, + messageId: 'forbiddenRequires' + }) + + isResolve && + context.report({ + node, + messageId: 'forbiddenRequireResolve' + }) + + isModule && + context.report({ + node, + messageId: 'forbiddenModuleRequire' + }) + }, + MemberExpression(node) { + const isModule = + node.object?.name === 'module' && + ['children', 'exports', 'filename', 'id', 'isPreloading', 'loaded', 'parent', 'path', 'paths'].some( + property => node.property?.name === property + ) + + const isRequire = + node.object?.name === 'require' && + ['cache', 'extensions', 'main'].some(property => node.property?.name === property) + + isModule && + context.report({ + node, + messageId: 'forbiddenExports' + }) + + isRequire && + context.report({ + node, + messageId: 'forbiddenRequiresObjects' + }) + }, + Identifier(node) { + node.name === '__filename' && + context.report({ + node, + messageId: 'forbidden__filename' + }) + + node.name === '__dirname' && + context.report({ + node, + messageId: 'forbidden__dirname' + }) + } + } + } +} diff --git a/packages/eslint-plugin-sui/src/rules/decorators.js b/packages/eslint-plugin-sui/src/rules/decorators.js new file mode 100644 index 000000000..9c524de80 --- /dev/null +++ b/packages/eslint-plugin-sui/src/rules/decorators.js @@ -0,0 +1,86 @@ +/** + * @fileoverview Ensure that at least all your UseCases are using @inlineError and @tracer decorator from sui + */ +'use strict' + +const dedent = require('string-dedent') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Ensure that at least all your UseCases are using @inlineError and @tracer decorator from sui', + recommended: true, + url: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements' + }, + fixable: 'code', + schema: [], + messages: { + missingInlineError: dedent` + All our UseCases must have an @inlineError decorator. + `, + missingTracer: dedent` + All our UseCases must have a @tracer() decorator. + `, + tracerMissCall: dedent` + Your tracer decorator should be call always with the name of your class + `, + inlineErrorMissplace: dedent` + the inlineError decorator should be always the first + ` + } + }, + create: function (context) { + return { + MethodDefinition(node) { + const className = node.parent?.parent?.id?.name + const shouldExtendFromUseCase = node.parent?.parent?.superClass?.name === 'UseCase' + const isExecute = node.key?.name === 'execute' && shouldExtendFromUseCase + const hasInlineError = node.decorators?.some(node => node.expression?.name === 'inlineError') + const tracerNode = node.decorators?.find(node => node.expression?.callee?.name === 'tracer') + const isTracerCalledWithClassName = + tracerNode?.expression?.callee?.name === 'tracer' && + className + '#' + node.key?.name === tracerNode?.expression?.arguments[0]?.properties[0]?.value?.value && + tracerNode?.expression?.arguments[0]?.properties[0]?.key?.name === 'metric' + const isInlineErrorTheFirst = node.decorators?.at(-1)?.expression?.name === 'inlineError' + + isExecute && + !hasInlineError && + context.report({ + node: node.key, + messageId: 'missingInlineError' + }) + + isExecute && + hasInlineError && + !isInlineErrorTheFirst && + context.report({ + node: node.key, + messageId: 'inlineErrorMissplace' + }) + + isExecute && + !tracerNode && + context.report({ + node: node.key, + messageId: 'missingTracer' + }) + + tracerNode && + !isTracerCalledWithClassName && + context.report({ + node: tracerNode, + messageId: 'tracerMissCall', + fix(fixer) { + return fixer.replaceText(tracerNode.expression, `tracer({metric: '${className}#${node.key?.name}'})`) + } + }) + } + } + } +} diff --git a/packages/eslint-plugin-sui/src/rules/forbidden-require.js b/packages/eslint-plugin-sui/src/rules/forbidden-require.js deleted file mode 100644 index 5e31b845b..000000000 --- a/packages/eslint-plugin-sui/src/rules/forbidden-require.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @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: 'https://github.mpi-internal.com/scmspain/es-td-agreements/blob/master/30-Frontend/00-agreements' - }, - 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/test/server/commonjs.js b/packages/eslint-plugin-sui/test/server/commonjs.js new file mode 100644 index 000000000..a527b088b --- /dev/null +++ b/packages/eslint-plugin-sui/test/server/commonjs.js @@ -0,0 +1,156 @@ +import dedent from 'dedent' +import {RuleTester} from 'eslint' + +import rule from '../../src/rules/commonjs.js' + +const resolvedBabelPresetSui = require.resolve('babel-preset-sui') +const parser = require.resolve('@babel/eslint-parser') + +// ------------------------------------------------------------------------------ +// Tests +// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({parser, parserOptions: {babelOptions: {configFile: resolvedBabelPresetSui}}}) +ruleTester.run('esm', rule, { + valid: [ + { + code: dedent` + class User { + static create() { return new User() } + } + ` + }, + { + code: dedent` + import { createRequire } from "module" + const require = createRequire(import.meta.url) + + require('whatever') + + class User { + static create() { return new User() } + } + ` + } + ], + + invalid: [ + { + code: dedent` + class Model { + constructor() { this.name = 'John Doe' } + } + module.exports = Model + `, + errors: [ + { + message: dedent` + Use module.* should be avoid. + ` + } + ] + }, + { + code: dedent` + const deps = require('my-dep') + class Config { + static create() { + return {API_URL: 'google.com'} + } + } + `, + errors: [ + { + message: dedent` + Use require function should be avoid. + ` + } + ] + }, + { + code: dedent` + const path = require.resolve('my-dep') + `, + errors: [ + { + message: dedent` + Use require.resolve function should be avoid. + ` + } + ] + }, + { + code: dedent` + console.log(require.main) + `, + errors: [ + { + message: dedent` + Use require.cache or require.extensions or require.main should be avoid. + ` + } + ] + }, + { + code: dedent` + console.log(require.cache) + `, + errors: [ + { + message: dedent` + Use require.cache or require.extensions or require.main should be avoid. + ` + } + ] + }, + { + code: dedent` + console.log(require.extensions) + `, + errors: [ + { + message: dedent` + Use require.cache or require.extensions or require.main should be avoid. + ` + } + ] + }, + { + code: dedent` + console.log(__dirname) + `, + errors: [ + { + message: dedent` + __dirname should be avoid + ` + } + ] + }, + { + code: dedent` + console.log(__filename) + `, + errors: [ + { + message: dedent` + __filename should be avoid + ` + } + ] + }, + { + code: dedent` + module.require(id) + `, + errors: [ + { + message: dedent` + Use module.require function should be avoid. + ` + } + ] + } + ] +}) diff --git a/packages/eslint-plugin-sui/test/server/decorators.js b/packages/eslint-plugin-sui/test/server/decorators.js new file mode 100644 index 000000000..d52ea4ee0 --- /dev/null +++ b/packages/eslint-plugin-sui/test/server/decorators.js @@ -0,0 +1,109 @@ +import dedent from 'dedent' +import {RuleTester} from 'eslint' + +import rule from '../../src/rules/decorators.js' + +// ------------------------------------------------------------------------------ +// Tests +// more info: https://eslint.org/docs/latest/integrate/nodejs-api#ruletester +// ------------------------------------------------------------------------------ + +const resolvedBabelPresetSui = require.resolve('babel-preset-sui') +const parser = require.resolve('@babel/eslint-parser') + +const ruleTester = new RuleTester({parser, parserOptions: {babelOptions: {configFile: resolvedBabelPresetSui}}}) +ruleTester.run('decorators', rule, { + valid: [ + { + code: dedent` + class MyUseCase extends UseCase { + + @tracer({metric: 'MyUseCase#execute'}) + @inlineError + execute(){} + } + ` + } + ], + + invalid: [ + { + code: dedent` + class MyUseCase extends UseCase { + + execute(){} + } + `, + errors: [ + { + message: dedent` + All our UseCases must have an @inlineError decorator. + ` + }, + { + message: dedent` + All our UseCases must have a @tracer() decorator. + ` + } + ] + }, + { + code: dedent` + class MyUseCase extends UseCase { + + @inlineError + execute(){} + } + `, + errors: [ + { + message: dedent` + All our UseCases must have a @tracer() decorator. + ` + } + ] + }, + { + code: dedent` + class MyUseCase extends UseCase { + + @tracer() + @inlineError + execute(){} + } + `, + output: dedent` + class MyUseCase extends UseCase { + + @tracer({metric: 'MyUseCase#execute'}) + @inlineError + execute(){} + } + `, + errors: [ + { + message: dedent` + Your tracer decorator should be call always with the name of your class + ` + } + ] + }, + { + code: dedent` + class MyUseCase extends UseCase { + + @inlineError + @tracer({metric: 'MyUseCase#execute'}) + execute(){} + } + `, + errors: [ + { + message: dedent` + the inlineError decorator should be always the first + ` + } + ] + } + ] +}) diff --git a/packages/sui-bundler/CHANGELOG.md b/packages/sui-bundler/CHANGELOG.md index d745c76a8..4c87473ce 100644 --- a/packages/sui-bundler/CHANGELOG.md +++ b/packages/sui-bundler/CHANGELOG.md @@ -1,5 +1,15 @@ # CHANGELOG +# 9.58.0 (2024-05-02) + + +### Features + +* move webpack dev server to patched version 4.15.2 ([5a291c0](https://github.com/SUI-Components/sui/commit/5a291c0ba1ee4f737f2a0b1578d66a2d9306cb36)) +* update to patched version to avoid vulnerabilities ([4144598](https://github.com/SUI-Components/sui/commit/41445982968d7908d5cb63148e603801b343e2ed)) + + + # 9.57.0 (2024-03-18) diff --git a/packages/sui-bundler/package.json b/packages/sui-bundler/package.json index 476db3c26..001cb0614 100644 --- a/packages/sui-bundler/package.json +++ b/packages/sui-bundler/package.json @@ -1,6 +1,6 @@ { "name": "@s-ui/bundler", - "version": "9.57.0", + "version": "9.58.0", "description": "Config-free bundler for ES6 React apps.", "bin": { "sui-bundler": "./bin/sui-bundler.js" @@ -56,7 +56,7 @@ "style-loader": "3.3.1", "swc-loader": "0.2.1", "url": "0.11.0", - "webpack-dev-server": "4.10.0", + "webpack-dev-server": "4.15.2", "webpack-manifest-plugin": "5.0.0", "webpack-node-externals": "3.0.0", "webpack": "5.82.1" diff --git a/packages/sui-ssr/CHANGELOG.md b/packages/sui-ssr/CHANGELOG.md index 16fa12f6b..0b5971147 100644 --- a/packages/sui-ssr/CHANGELOG.md +++ b/packages/sui-ssr/CHANGELOG.md @@ -1,5 +1,14 @@ # CHANGELOG +# 8.28.0 (2024-05-02) + + +### Features + +* update to patched version to avoid vulnerabilities ([6873ee4](https://github.com/SUI-Components/sui/commit/6873ee468b9b26810feb63e6d7aca99ed469def7)) + + + # 8.27.0 (2024-04-05) diff --git a/packages/sui-ssr/package.json b/packages/sui-ssr/package.json index 06a335303..820ff501b 100644 --- a/packages/sui-ssr/package.json +++ b/packages/sui-ssr/package.json @@ -1,6 +1,6 @@ { "name": "@s-ui/ssr", - "version": "8.27.0", + "version": "8.28.0", "description": "> Plug SSR to you SUI SPA.", "main": "index.js", "bin": { @@ -38,7 +38,7 @@ "noop-console": "0.8.0", "parse5": "6.0.1", "ua-parser-js": "0.7.33", - "webpack-dev-middleware": "6.1.1", + "webpack-dev-middleware": "6.1.2", "webpack-hot-middleware": "2.25.4", "nodemon": "3.0.1" } diff --git a/packages/sui-widget-embedder/CHANGELOG.md b/packages/sui-widget-embedder/CHANGELOG.md index 95dd3fdcd..1ec95b465 100644 --- a/packages/sui-widget-embedder/CHANGELOG.md +++ b/packages/sui-widget-embedder/CHANGELOG.md @@ -1,5 +1,14 @@ # CHANGELOG +# 6.3.0 (2024-05-02) + + +### Features + +* update to patched version to avoid vulnerabilities ([5af5a0b](https://github.com/SUI-Components/sui/commit/5af5a0b69dcd33a9f5e9c55654c92eec68f4a7b5)) + + + # 6.2.0 (2023-08-21) @@ -703,7 +712,4 @@ export sintaxis is not used anymore. If you're using it, check it in order to ge * **sui-widget-embedder:** build all pages automagicaly ([daf3ddc](https://github.com/SUI-Components/sui/commit/daf3ddcac1eda9476ff96c82a72f5d5da98f2bbb)) * **sui-widget-embedder:** create donwloader.js with the manifests of the assets ([856eae3](https://github.com/SUI-Components/sui/commit/856eae37ee6fedc0869f1fe51e4b64c3aab6cf8c)) * **sui-widget-embedder:** created Widgets components ([2a929fd](https://github.com/SUI-Components/sui/commit/2a929fd63c2e9ae81ae2bfcbfeef4fc7506501c2)) -* **sui-widget-embedder:** first commit ([447917f](https://github.com/SUI-Components/sui/commit/447917fc8579152571a479a62b27453e6802ad85)) - - - +* **sui-widget-embedder:** first commit ([447917f](https://github.com/SUI-Components/sui/commit/447917fc8579152571a479a62b27453e6802ad85)) \ No newline at end of file diff --git a/packages/sui-widget-embedder/package.json b/packages/sui-widget-embedder/package.json index 0b6af3717..fab57ea78 100644 --- a/packages/sui-widget-embedder/package.json +++ b/packages/sui-widget-embedder/package.json @@ -1,6 +1,6 @@ { "name": "@s-ui/widget-embedder", - "version": "6.2.0", + "version": "6.3.0", "description": "Embed React components to your app as widgets", "bin": { "sui-widget-embedder": "./bin/sui-widget-embedder.js" @@ -19,6 +19,6 @@ "@s-ui/react-hooks": "1", "commander": "8.3.0", "copy-paste": "1.3.0", - "webpack-dev-middleware": "5.3.3" + "webpack-dev-middleware": "5.3.4" } }