diff --git a/.github/workflows/eslint-config.yml b/.github/workflows/eslint-config.yml new file mode 100644 index 00000000..00e05754 --- /dev/null +++ b/.github/workflows/eslint-config.yml @@ -0,0 +1,44 @@ +name: eslint-config + +on: + push: + +env: + PROJECT_DIR: packages/eslint-config + NODE_VERSION: '14.18.1' + REGISTRY_URL: 'https://registry.npmjs.org' + +jobs: + build: + runs-on: ubuntu-latest + name: Build + steps: + - uses: actions/checkout@v3 + - name: Set up Node ${{ env.NODE_VERSION }} + uses: actions/setup-node@v3 + with: + node-version: ${{ env.NODE_VERSION }} + - run: yarn install --frozen-lockfile + working-directory: ${{ env.PROJECT_DIR }} + - name: Run the build script + run: yarn lint + working-directory: ${{ env.PROJECT_DIR }} + + release: + needs: build + runs-on: ubuntu-latest + name: Release + if: ${{ contains(github.ref, 'refs/tags/v') && contains(github.ref, github.workflow) }} + steps: + - uses: actions/checkout@v3 + - name: Set up Node ${{ env.NODE_VERSION }} + uses: actions/setup-node@v3 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: ${{ env.REGISTRY_URL }} + - run: yarn install --frozen-lockfile + working-directory: ${{ env.PROJECT_DIR }} + - run: yarn publish + working-directory: ${{ env.PROJECT_DIR }} + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/rubocop-cobra.yml b/.github/workflows/rubocop-cobra.yml new file mode 100644 index 00000000..bee022a3 --- /dev/null +++ b/.github/workflows/rubocop-cobra.yml @@ -0,0 +1,13 @@ +name: rubocop-cobra + +on: + push: + +jobs: + ruby: + uses: ./.github/workflows/_ruby-package.yml + with: + package: ${{ github.workflow }} + ruby: '["2.7.4", "3.1.2"]' + rails: '["any"]' + secrets: inherit diff --git a/.github/workflows/rubocop-powerhome.yml b/.github/workflows/rubocop-powerhome.yml new file mode 100644 index 00000000..e3c2f542 --- /dev/null +++ b/.github/workflows/rubocop-powerhome.yml @@ -0,0 +1,13 @@ +name: rubocop-powerhome + +on: + push: + +jobs: + ruby: + uses: ./.github/workflows/_ruby-package.yml + with: + package: ${{ github.workflow }} + ruby: '["2.7.4", "3.1.2"]' + rails: '["7.0.3.1","6.1.6.1","6.0.5.1","5.2.8.1"]' + secrets: inherit diff --git a/docs/README.md b/docs/README.md index 33a1e3fa..e0f20be4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,6 +22,18 @@ Lumberaxe handles logging output formatting. Consent provides permission-based authorization. +[rubocop-powerhome](https://github.com/powerhome/power-tools/blob/main/packages/rubocop-powerhome/docs/README.md) 💎 + +This gem is focused on providing standard rubocop configuration for Power Home Remodeling ruby apps. See more in [`rubocop-powerhome`](../packages/rubocop-powerhome). + +[rubocop-cobra](https://github.com/powerhome/power-tools/blob/main/packages/rubocop-cobra/docs/README.md) 💎 + +This gem is focused on providing Cops to support a healthy cobra app development. See more in [`rubocop-cobra`](../packages/rubocop-cobra). + +[@powerhome/eslint-config](https://github.com/powerhome/power-tools/blob/main/packages/eslint-config/docs/README.md) + +Shared eslint-config from Power Home Remodeling. + ## Installation 🛠 These packages are all meant to install inside of an application and aren't intended to stand alone; currently, they are all published to [RubyGems](https://rubygems.org/) and you can use standard Bundler methods to install them. diff --git a/packages/audit_tracker/spec/internal/config/initializers/audit_tracker.rb b/packages/audit_tracker/spec/internal/config/initializers/audit_tracker.rb index 30718fbf..40c0b35d 100644 --- a/packages/audit_tracker/spec/internal/config/initializers/audit_tracker.rb +++ b/packages/audit_tracker/spec/internal/config/initializers/audit_tracker.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +# rubocop:disable RSpec/FactoryBot/ConsistentParenthesesStyle AuditTracker.setup do tracker(:user) do create :created_by, foreign_key: :created_by_id, class_name: "::Internal::User" @@ -16,3 +17,4 @@ value: ->(object) { object&.updated_by&.department } end end +# rubocop:enable RSpec/FactoryBot/ConsistentParenthesesStyle diff --git a/packages/eslint-config/.eslintrc.json b/packages/eslint-config/.eslintrc.json new file mode 100644 index 00000000..b7052c91 --- /dev/null +++ b/packages/eslint-config/.eslintrc.json @@ -0,0 +1 @@ +{ "extends": "@powerhome/eslint-config/base" } diff --git a/packages/eslint-config/.gitignore b/packages/eslint-config/.gitignore new file mode 100644 index 00000000..8f2b90af --- /dev/null +++ b/packages/eslint-config/.gitignore @@ -0,0 +1,4 @@ +.tmp +node_modules/ +**/*.d.ts +**/*.d.ts.map diff --git a/packages/eslint-config/docs/README.md b/packages/eslint-config/docs/README.md new file mode 100644 index 00000000..4bfcdd80 --- /dev/null +++ b/packages/eslint-config/docs/README.md @@ -0,0 +1,48 @@ +# @powerhome/eslint-config + +Provides eslint-config for Power Home Remodeling apps. + +## Installation + +Add this line to your application's package.json: + +```ruby + "devDependencies": { + ... + "@powerhome/eslint-config": "0.1.0", + ... + } +``` + +And then yarn: + + $ yarn + +## Usage + +Assuming it's a typescript app, add an `extends` line to your `.eslintrc.json`: + +```js +{ + ... + extends: [ + ... + "@powerhome", + ], + ... +} +``` + +That's it! You can override the standard configuration after that. + +## Flow type apps + +For flow-based apps, replace `@powerhome` by `@powerhome/eslint-config/flow`. Note that usage of Flow at Power is not recommended, and all projects should migrate to TypeScript; this set of rules is provided only for transitionary purposes and will be removed in future releases. + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/powerhome/power_linting. + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/packages/eslint-config/lib/base.js b/packages/eslint-config/lib/base.js new file mode 100644 index 00000000..d3f29a5a --- /dev/null +++ b/packages/eslint-config/lib/base.js @@ -0,0 +1,67 @@ +module.exports = { + root: true, + plugins: ["jsx-control-statements", "react", "react-hooks"], + extends: [ + "eslint:recommended", + "plugin:jsx-control-statements/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + ], + parser: "babel-eslint", + parserOptions: { + ecmaVersion: 6, + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, + }, + env: { + browser: true, + es6: true, + "jsx-control-statements/jsx-control-statements": true, + node: true, + mocha: true, + }, + rules: { + "jsx-control-statements/jsx-jcs-no-undef": 1, + "no-console": 1, + "no-restricted-globals": [1, { name: "moment" }], + "no-use-before-define": [2, { functions: true, classes: true }], + "react/forbid-prop-types": 2, + "react/jsx-boolean-value": 2, + "react/jsx-closing-bracket-location": 1, + "react/jsx-curly-spacing": 2, + "react/jsx-handler-names": 2, + "react/jsx-indent-props": 2, + "react/jsx-key": 2, + "react/jsx-max-props-per-line": 2, + "react/jsx-no-bind": 0, + "react/jsx-no-literals": 1, + "react/jsx-no-undef": [2, { allowGlobals: true }], + "react/jsx-pascal-case": 2, + "react/jsx-sort-props": 2, + "react/jsx-wrap-multilines": 2, + "react/no-danger": 1, + "react/no-did-mount-set-state": 2, + "react/no-did-update-set-state": 2, + "react/no-multi-comp": 1, + "react/no-set-state": 1, + "react/prefer-es6-class": 2, + "react/prop-types": 1, + "react/self-closing-comp": 2, + "react/sort-comp": 1, + }, + settings: { + react: { + version: "detect", + }, + }, + ignorePatterns: [ + "**/*.d.ts", + "coverage/**/*", + "doc/**/*", + "node_modules/**/*", + "spec/dummy/**/*", + "vendor/**/*", + ], +} diff --git a/packages/eslint-config/lib/flow.js b/packages/eslint-config/lib/flow.js new file mode 100644 index 00000000..4c054eaa --- /dev/null +++ b/packages/eslint-config/lib/flow.js @@ -0,0 +1,8 @@ +module.exports = { + extends: [ + "@powerhome/eslint-config/base", + "plugin:flowtype/recommended" + ], + plugins: ["flowtype"], + ignorePatterns: ["flow-typed/**/*"], +} diff --git a/packages/eslint-config/lib/typescript.js b/packages/eslint-config/lib/typescript.js new file mode 100644 index 00000000..e30e5643 --- /dev/null +++ b/packages/eslint-config/lib/typescript.js @@ -0,0 +1,24 @@ +module.exports = { + extends: ["@powerhome/eslint-config/base"], + overrides: [ + { + files: ["**/*.ts", "**/*.tsx"], + extends: ["plugin:@typescript-eslint/recommended"], + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint"], + rules: { + "flowtype/no-types-missing-file-annotation": 0, + "jsx-control-statements/jsx-use-if-tag": 0, + "no-use-before-define": 0, + "@typescript-eslint/no-array-constructor": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/no-var-requires": 0, + "@typescript-eslint/no-unused-vars": 1, + "@typescript-eslint/no-use-before-define": [ + 2, + { functions: true, classes: true }, + ], + }, + }, + ], +} diff --git a/packages/eslint-config/mkdocs.yml b/packages/eslint-config/mkdocs.yml new file mode 100644 index 00000000..69418b62 --- /dev/null +++ b/packages/eslint-config/mkdocs.yml @@ -0,0 +1,9 @@ +site_name: ESLint Config Powerhome +site_description: Provides eslint-config for Power Home Remodeling apps +repo_url: https://github.com/powerhome/power_linting +edit_uri: edit/main/eslint-config/docs/ +nav: + - 'Home': 'README.md' + +plugins: + - techdocs-core diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json new file mode 100644 index 00000000..c1bc3f1d --- /dev/null +++ b/packages/eslint-config/package.json @@ -0,0 +1,46 @@ +{ + "name": "@powerhome/eslint-config", + "version": "0.1.0", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "exports": { + "./base": "./lib/base.js", + "./flow": "./lib/flow.js", + "./typescript": "./lib/typescript.js", + ".": "./lib/typescript.js" + }, + "keywords": [ + "eslint", + "eslintconfig" + ], + "scripts": { + "lint": "eslint lib/*" + }, + "peerDependencies": { + "eslint": "7.32.0", + "eslint-plugin-flowtype": "8.0.3", + "eslint-plugin-jsx-control-statements": "3.0.0", + "eslint-plugin-react": "7.31.10", + "eslint-plugin-react-hooks": "4.6.0", + "eslint-webpack-plugin": "3.2.0", + "@typescript-eslint/eslint-plugin": "5.41.0", + "@typescript-eslint/parser": "5.41.0", + "babel-eslint": "8 || 10", + "typescript": "4.8.4" + }, + "devDependencies": { + "semver": "7.3.8", + "eslint": "7.32.0", + "eslint-plugin-flowtype": "8.0.3", + "eslint-plugin-jsx-control-statements": "3.0.0", + "eslint-plugin-react": "7.31.10", + "eslint-plugin-react-hooks": "4.6.0", + "eslint-webpack-plugin": "3.2.0", + "@typescript-eslint/eslint-plugin": "5.41.0", + "@typescript-eslint/parser": "5.41.0", + "babel-eslint": "10.1.0", + "typescript": "4.8.4" + } +} diff --git a/packages/eslint-config/yarn.lock b/packages/eslint-config/yarn.lock new file mode 100644 index 00000000..5a5b945c --- /dev/null +++ b/packages/eslint-config/yarn.lock @@ -0,0 +1,1738 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/generator@^7.19.6": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.6.tgz#9e481a3fe9ca6261c972645ae3904ec0f9b34a1d" + integrity sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA== + dependencies: + "@babel/types" "^7.19.4" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-function-name@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" + integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== + dependencies: + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.18.10", "@babel/parser@^7.19.6", "@babel/parser@^7.7.0": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.6.tgz#b923430cb94f58a7eae8facbffa9efd19130e7f8" + integrity sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA== + +"@babel/template@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + +"@babel/traverse@^7.7.0": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.6.tgz#7b4c865611df6d99cb131eec2e8ac71656a490dc" + integrity sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.19.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.19.6" + "@babel/types" "^7.19.4" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.19.4", "@babel/types@^7.7.0": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.4.tgz#0dd5c91c573a202d600490a35b33246fed8a41c7" + integrity sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" + integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@types/eslint@^7.29.0 || ^8.4.1": + version "8.4.7" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.7.tgz#0f05a2677d1a394ff70c21a964a32d3efa05f966" + integrity sha512-ehM7cCt2RSFs42mb+lcmhFT9ouIlV92PuaeRGn8N8c98oMjG4Z5pJHA9b1QiCcuqnbPSHcyfiD3mlhqMaHsQIw== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" + integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== + +"@types/json-schema@*", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/node@*": + version "18.11.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.4.tgz#7017a52e18dfaad32f55eebd539993014441949c" + integrity sha512-BxcJpBu8D3kv/GZkx/gSMz6VnTJREBj/4lbzYOQueUOELkt8WrO6zAcSPmp9uRPEW/d+lUO8QK0W2xnS1hEU0A== + +"@types/semver@^7.3.12": + version "7.3.12" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.12.tgz#920447fdd78d76b19de0438b7f60df3c4a80bf1c" + integrity sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A== + +"@typescript-eslint/eslint-plugin@5.41.0": + version "5.41.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.41.0.tgz#f8eeb1c6bb2549f795f3ba71aec3b38d1ab6b1e1" + integrity sha512-DXUS22Y57/LAFSg3x7Vi6RNAuLpTXwxB9S2nIA7msBb/Zt8p7XqMwdpdc1IU7CkOQUPgAqR5fWvxuKCbneKGmA== + dependencies: + "@typescript-eslint/scope-manager" "5.41.0" + "@typescript-eslint/type-utils" "5.41.0" + "@typescript-eslint/utils" "5.41.0" + debug "^4.3.4" + ignore "^5.2.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@5.41.0": + version "5.41.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.41.0.tgz#0414a6405007e463dc527b459af1f19430382d67" + integrity sha512-HQVfix4+RL5YRWZboMD1pUfFN8MpRH4laziWkkAzyO1fvNOY/uinZcvo3QiFJVS/siNHupV8E5+xSwQZrl6PZA== + dependencies: + "@typescript-eslint/scope-manager" "5.41.0" + "@typescript-eslint/types" "5.41.0" + "@typescript-eslint/typescript-estree" "5.41.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.41.0": + version "5.41.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.41.0.tgz#28e3a41d626288d0628be14cf9de8d49fc30fadf" + integrity sha512-xOxPJCnuktUkY2xoEZBKXO5DBCugFzjrVndKdUnyQr3+9aDWZReKq9MhaoVnbL+maVwWJu/N0SEtrtEUNb62QQ== + dependencies: + "@typescript-eslint/types" "5.41.0" + "@typescript-eslint/visitor-keys" "5.41.0" + +"@typescript-eslint/type-utils@5.41.0": + version "5.41.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.41.0.tgz#2371601171e9f26a4e6da918a7913f7266890cdf" + integrity sha512-L30HNvIG6A1Q0R58e4hu4h+fZqaO909UcnnPbwKiN6Rc3BUEx6ez2wgN7aC0cBfcAjZfwkzE+E2PQQ9nEuoqfA== + dependencies: + "@typescript-eslint/typescript-estree" "5.41.0" + "@typescript-eslint/utils" "5.41.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.41.0": + version "5.41.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.41.0.tgz#6800abebc4e6abaf24cdf220fb4ce28f4ab09a85" + integrity sha512-5BejraMXMC+2UjefDvrH0Fo/eLwZRV6859SXRg+FgbhA0R0l6lDqDGAQYhKbXhPN2ofk2kY5sgGyLNL907UXpA== + +"@typescript-eslint/typescript-estree@5.41.0": + version "5.41.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.41.0.tgz#bf5c6b3138adbdc73ba4871d060ae12c59366c61" + integrity sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg== + dependencies: + "@typescript-eslint/types" "5.41.0" + "@typescript-eslint/visitor-keys" "5.41.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.41.0": + version "5.41.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.41.0.tgz#f41ae5883994a249d00b2ce69f4188f3a23fa0f9" + integrity sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.41.0" + "@typescript-eslint/types" "5.41.0" + "@typescript-eslint/typescript-estree" "5.41.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.41.0": + version "5.41.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.41.0.tgz#d3510712bc07d5540160ed3c0f8f213b73e3bcd9" + integrity sha512-vilqeHj267v8uzzakbm13HkPMl7cbYpKVjgFWZPIOHIJHZtinvypUhJ5xBXfWYg4eFKqztbMMpOgFpT9Gfx4fw== + dependencies: + "@typescript-eslint/types" "5.41.0" + eslint-visitor-keys "^3.3.0" + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.0.1, ajv@^8.8.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-includes@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb" + integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.flatmap@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz#a7e8ed4225f4788a70cd910abcf0791e76a5534f" + integrity sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.2" + es-shim-unscopables "^1.0.0" + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +babel-eslint@10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" + integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-properties@^1.1.3, define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +enquirer@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5: + version "1.20.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.4.tgz#1d103f9f8d78d4cf0713edcd6d0ed1a46eed5861" + integrity sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.3" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.2" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + safe-regex-test "^1.0.0" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" + +es-shim-unscopables@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" + integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + dependencies: + has "^1.0.3" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-plugin-flowtype@8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz#e1557e37118f24734aa3122e7536a038d34a4912" + integrity sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ== + dependencies: + lodash "^4.17.21" + string-natural-compare "^3.0.1" + +eslint-plugin-jsx-control-statements@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-control-statements/-/eslint-plugin-jsx-control-statements-3.0.0.tgz#89d29cb0d167a6ba301f41dee948bb114a8a73b4" + integrity sha512-OAlTFVT6jyLXO6BVwYnlE95wKsT9LLRDs57+eOaDZjymTks7OYo0QEIfokKLfGrhfdgzAQz9Gsk5GqnVJbT/wg== + +eslint-plugin-react-hooks@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== + +eslint-plugin-react@7.31.10: + version "7.31.10" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz#6782c2c7fe91c09e715d536067644bbb9491419a" + integrity sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA== + dependencies: + array-includes "^3.1.5" + array.prototype.flatmap "^1.3.0" + doctrine "^2.1.0" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.5" + object.fromentries "^2.0.5" + object.hasown "^1.1.1" + object.values "^1.1.5" + prop-types "^15.8.1" + resolve "^2.0.0-next.3" + semver "^6.3.0" + string.prototype.matchall "^4.0.7" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint-webpack-plugin@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz#1978cdb9edc461e4b0195a20da950cf57988347c" + integrity sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w== + dependencies: + "@types/eslint" "^7.29.0 || ^8.4.1" + jest-worker "^28.0.2" + micromatch "^4.0.5" + normalize-path "^3.0.0" + schema-utils "^4.0.0" + +eslint@7.32.0: + version "7.32.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" + integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.17.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" + integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +jest-worker@^28.0.2: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98" + integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +"jsx-ast-utils@^2.4.1 || ^3.0.0": + version "3.3.3" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" + integrity sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw== + dependencies: + array-includes "^3.1.5" + object.assign "^4.1.3" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.12.2, object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.3, object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.entries@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.fromentries@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" + integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.hasown@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.1.tgz#ad1eecc60d03f49460600430d97f23882cf592a3" + integrity sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A== + dependencies: + define-properties "^1.1.4" + es-abstract "^1.19.5" + +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + +regexpp@^3.1.0, regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.12.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.3: + version "2.0.0-next.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" + integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +semver@7.3.8, semver@^7.2.1, semver@^7.3.7: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +string-natural-compare@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" + integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== + +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.matchall@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" + integrity sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.4.1" + side-channel "^1.0.4" + +string.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +table@^6.0.9: + version "6.8.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" + integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +typescript@4.8.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== diff --git a/packages/rubocop-cobra/.gitignore b/packages/rubocop-cobra/.gitignore new file mode 100644 index 00000000..802a9756 --- /dev/null +++ b/packages/rubocop-cobra/.gitignore @@ -0,0 +1,10 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/pkg/ +/spec/reports/ +/tmp/ + +# rspec failure tracking +.rspec_status diff --git a/packages/rubocop-cobra/.rubocop.yml b/packages/rubocop-cobra/.rubocop.yml new file mode 100644 index 00000000..9dd64c0b --- /dev/null +++ b/packages/rubocop-cobra/.rubocop.yml @@ -0,0 +1,11 @@ +inherit_from: .rubocop_todo.yml + +require: + - rubocop-powerhome + +Naming/FileName: + Exclude: + - lib/rubocop-cobra.rb + +Rails: + Enabled: false diff --git a/packages/rubocop-cobra/.rubocop_todo.yml b/packages/rubocop-cobra/.rubocop_todo.yml new file mode 100644 index 00000000..253eae5d --- /dev/null +++ b/packages/rubocop-cobra/.rubocop_todo.yml @@ -0,0 +1,23 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2022-05-18 20:49:51 UTC using RuboCop version 1.29.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 2 +# Configuration parameters: IgnoredMethods, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 19 + +# Offense count: 14 +# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. +# IgnoredMethods: refine +Metrics/BlockLength: + Max: 97 + +# Offense count: 2 +# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. +Metrics/MethodLength: + Max: 11 diff --git a/packages/rubocop-cobra/CHANGELOG.md b/packages/rubocop-cobra/CHANGELOG.md new file mode 100644 index 00000000..5f2878b3 --- /dev/null +++ b/packages/rubocop-cobra/CHANGELOG.md @@ -0,0 +1,9 @@ +## [Unreleased] + +## [0.4.0] - 2022-06-01 + +- Adds Cobra/ViewComponentFilePlacement cop + +## [0.1.0] - 2022-05-18 + +- Initial release diff --git a/packages/rubocop-cobra/Gemfile b/packages/rubocop-cobra/Gemfile new file mode 100644 index 00000000..17399bce --- /dev/null +++ b/packages/rubocop-cobra/Gemfile @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# Specify your gem's dependencies in rubocop-cobra.gemspec +gemspec + +gem "rake", "~> 13.0" +gem "rspec", "~> 3.0" +gem "rubocop", "~> 1.37.0" + +gem "rubocop-powerhome", path: "../rubocop-powerhome" diff --git a/packages/rubocop-cobra/Gemfile.lock b/packages/rubocop-cobra/Gemfile.lock new file mode 100644 index 00000000..bb2f6c89 --- /dev/null +++ b/packages/rubocop-cobra/Gemfile.lock @@ -0,0 +1,119 @@ +PATH + remote: ../rubocop-powerhome + specs: + rubocop-powerhome (0.5.0) + rubocop + rubocop-performance + rubocop-rails + rubocop-rake + rubocop-rspec + +PATH + remote: . + specs: + rubocop-cobra (0.4.0) + rubocop + rubocop-powerhome + +GEM + remote: https://rubygems.org/ + specs: + activesupport (7.0.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + ast (2.4.2) + byebug (11.1.3) + coderay (1.1.3) + concurrent-ruby (1.1.10) + diff-lcs (1.5.0) + i18n (1.12.0) + concurrent-ruby (~> 1.0) + json (2.6.2) + license_finder (7.0.1) + bundler + rubyzip (>= 1, < 3) + thor (~> 1.2) + tomlrb (>= 1.3, < 2.1) + with_env (= 1.1.0) + xml-simple (~> 1.1.9) + method_source (1.0.0) + minitest (5.16.3) + parallel (1.22.1) + parser (3.1.2.1) + ast (~> 2.4.1) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.9.0) + byebug (~> 11.0) + pry (~> 0.13.0) + rack (3.0.0) + rainbow (3.1.1) + rake (13.0.6) + regexp_parser (2.6.0) + rexml (3.2.5) + rspec (3.11.0) + rspec-core (~> 3.11.0) + rspec-expectations (~> 3.11.0) + rspec-mocks (~> 3.11.0) + rspec-core (3.11.0) + rspec-support (~> 3.11.0) + rspec-expectations (3.11.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.11.0) + rspec-mocks (3.11.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.11.0) + rspec-support (3.11.1) + rubocop (1.37.1) + json (~> 2.3) + parallel (~> 1.10) + parser (>= 3.1.2.1) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.23.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.23.0) + parser (>= 3.1.1.0) + rubocop-performance (1.15.0) + rubocop (>= 1.7.0, < 2.0) + rubocop-ast (>= 0.4.0) + rubocop-rails (2.17.0) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.33.0, < 2.0) + rubocop-rake (0.6.0) + rubocop (~> 1.0) + rubocop-rspec (2.14.1) + rubocop (~> 1.33) + ruby-progressbar (1.11.0) + rubyzip (2.3.2) + thor (1.2.1) + tomlrb (2.0.3) + tzinfo (2.0.5) + concurrent-ruby (~> 1.0) + unicode-display_width (2.3.0) + with_env (1.1.0) + xml-simple (1.1.9) + rexml + +PLATFORMS + arm64-darwin-21 + x86_64-darwin-21 + x86_64-linux + +DEPENDENCIES + license_finder (~> 7.0) + pry-byebug (= 3.9.0) + rake (~> 13.0) + rspec (~> 3.0) + rubocop (~> 1.37.0) + rubocop-cobra! + rubocop-powerhome! + +BUNDLED WITH + 2.3.14 diff --git a/packages/rubocop-cobra/LICENSE.txt b/packages/rubocop-cobra/LICENSE.txt new file mode 100644 index 00000000..fde926f5 --- /dev/null +++ b/packages/rubocop-cobra/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright Power Home Remodeling Group, LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/rubocop-cobra/Rakefile b/packages/rubocop-cobra/Rakefile new file mode 100644 index 00000000..7efc1316 --- /dev/null +++ b/packages/rubocop-cobra/Rakefile @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" + +require "rspec/core/rake_task" +RSpec::Core::RakeTask.new(:spec) + +require "rubocop/rake_task" +RuboCop::RakeTask.new(:rubocop) + +task default: %i[spec rubocop] + +desc "Generate a new cop with a template" +task :new_cop, [:cop] do |_task, args| + require "rubocop" + + cop_name = args.fetch(:cop) do + warn "usage: bundle exec rake new_cop[Department/Name]" + exit! + end + + generator = RuboCop::Cop::Generator.new(cop_name) + + generator.write_source + generator.write_spec + generator.inject_require(root_file_path: "lib/rubocop/cop/cobra_cops.rb") + generator.inject_config(config_file_path: "config/default.yml") + + puts generator.todo +end diff --git a/packages/rubocop-cobra/bin/console b/packages/rubocop-cobra/bin/console new file mode 100755 index 00000000..095a2ac0 --- /dev/null +++ b/packages/rubocop-cobra/bin/console @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "bundler/setup" +require "rubocop/cobra" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# (If you use this, don't forget to add pry to your Gemfile!) +# require "pry" +# Pry.start + +require "irb" +IRB.start(__FILE__) diff --git a/packages/rubocop-cobra/bin/rubocop b/packages/rubocop-cobra/bin/rubocop new file mode 100755 index 00000000..d0c48829 --- /dev/null +++ b/packages/rubocop-cobra/bin/rubocop @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rubocop' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rubocop", "rubocop") diff --git a/packages/rubocop-cobra/bin/setup b/packages/rubocop-cobra/bin/setup new file mode 100755 index 00000000..dce67d86 --- /dev/null +++ b/packages/rubocop-cobra/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/packages/rubocop-cobra/config/default.yml b/packages/rubocop-cobra/config/default.yml new file mode 100644 index 00000000..45da3894 --- /dev/null +++ b/packages/rubocop-cobra/config/default.yml @@ -0,0 +1,62 @@ +Cobra: + Enabled: true + +Cobra/CommandFilePlacement: + Description: 'This cop disallows adding global helpers to the `app/commands` directory.' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/ControllerFilePlacement: + Description: 'This cop disallows adding global controllers to the `app/controllers` directory.' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/DependencyVersion: + Description: 'External component dependencies should be declared with a version' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/GemRequirement: + Description: 'Component Gemfile dependencies must specify "require: nil"' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/HelperFilePlacement: + Description: 'This cop disallows adding global helpers to the `app/helpers` directory.' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/Inheritance: + Description: 'Enforce classes inherit from their own modularized parent classes' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/JobFilePlacement: + Description: 'This cop disallows adding global jobs to the `app/jobs` directory.' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/LibFilePlacement: + Description: 'This cop disallows adding library files directly into the `lib/` directory.' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/MailerFilePlacement: + Description: 'This cop disallows adding global helpers to the `app/mailers` directory.' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/ModelFilePlacement: + Description: 'This cop disallows adding global models to the `app/models` directory.' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/PresenterFilePlacement: + Description: 'This cop disallows adding global presenters to the `app/presenters` directory.' + Enabled: true + VersionAdded: '0.1.0' + +Cobra/ViewComponentFilePlacement: + Description: 'This cop disallows adding global view_components to the `app/components` directory.' + Enabled: true + VersionAdded: '0.4.0' diff --git a/packages/rubocop-cobra/doc/dependency_decisions.yml b/packages/rubocop-cobra/doc/dependency_decisions.yml new file mode 100644 index 00000000..f734baa9 --- /dev/null +++ b/packages/rubocop-cobra/doc/dependency_decisions.yml @@ -0,0 +1,3 @@ +--- +- - :inherit_from + - https://raw.githubusercontent.com/powerhome/oss-guide/master/license_rules.yml diff --git a/packages/rubocop-cobra/docs/README.md b/packages/rubocop-cobra/docs/README.md new file mode 100644 index 00000000..2642d673 --- /dev/null +++ b/packages/rubocop-cobra/docs/README.md @@ -0,0 +1,40 @@ +# Rubocop::Cobra + +This gem is focused on providing Cops to support a healthy cobra app development (see https://cbra.info and https://github.com/powerhome/cobra_commander). + +## Installation + +Add this line to your application's Gemfile under development: + +```ruby +gem "rubocop-cobra", require: false +``` + +And then execute: + + $ bundle install + +## Usage + +Add a `require` line to your `.rubocop.yml`: + +```yml +require: + - rubocop-cobra +``` + +That's it! You can override the standard configuration after that. + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/powerhome/power_linting/rubocop-cobra. + +## License + +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/packages/rubocop-cobra/lib/rubocop-cobra.rb b/packages/rubocop-cobra/lib/rubocop-cobra.rb new file mode 100644 index 00000000..0aa54761 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop-cobra.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require "rubocop" + +require_relative "rubocop/cobra" + +RuboCop::Cobra::Inject.defaults! + +require_relative "rubocop/cop/cobra_cops" diff --git a/packages/rubocop-cobra/lib/rubocop/cobra.rb b/packages/rubocop-cobra/lib/rubocop/cobra.rb new file mode 100644 index 00000000..7b129107 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cobra.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module RuboCop + # @private + module Cobra + class Error < StandardError; end + + PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze + CONFIG_DEFAULT = PROJECT_ROOT.join("config", "default.yml").freeze + CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze + + private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT) + + require_relative "cobra/inject" + require_relative "cobra/version" + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cobra/inject.rb b/packages/rubocop-cobra/lib/rubocop/cobra/inject.rb new file mode 100644 index 00000000..a1915c65 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cobra/inject.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# The original code is from https://github.com/rubocop/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb +# See https://github.com/rubocop/rubocop-rspec/blob/master/MIT-LICENSE.md +module RuboCop + module Cobra + # Because RuboCop doesn't yet support plugins, we have to monkey patch in a + # bit of our configuration. + module Inject + def self.defaults! + path = CONFIG_DEFAULT.to_s + hash = ConfigLoader.send(:load_yaml_configuration, path) + config = Config.new(hash, path).tap(&:make_excludes_absolute) + Rails.logger.debug { "configuration from #{path}" } if ConfigLoader.debug? + config = ConfigLoader.merge_with_default(config, path) + ConfigLoader.instance_variable_set(:@default_configuration, config) + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cobra/version.rb b/packages/rubocop-cobra/lib/rubocop/cobra/version.rb new file mode 100644 index 00000000..07a5bc92 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cobra/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module RuboCop + module Cobra + VERSION = "0.4.0" + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/command_file_placement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/command_file_placement.rb new file mode 100644 index 00000000..a6e65bae --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/command_file_placement.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + # This cop disallows adding global helpers to the `app/commands` directory. + # + # The goal is to encourage developers to put new command files inside the correct + # namespace, where they can be more modularly isolated and ownership is clear. + # + # @example + # # bad + # # path: components/my_component/app/commands/foo.rb + # class Foo + # # ... + # end + # + # # good + # # path: components/my_component/app/commands/my_component/foo.rb + # module MyComponent + # class Foo + # # ... + # end + # end + # + class CommandFilePlacement < RuboCop::Cop::Cop + include FilePlacementHelp + + def investigate(processed_source) + return if processed_source.blank? + + path = processed_source.file_path + return unless applicable_component_path?(path, commands_path) + return if namespaced_correctly?(path, commands_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, commands_path)) + end + + private + + def commands_path + "app/commands/" + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/controller_file_placement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/controller_file_placement.rb new file mode 100644 index 00000000..b31a8f6b --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/controller_file_placement.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + # This cop disallows adding global controllers to the `app/controllers` directory. + # + # The goal is to encourage developers to put new controllers inside the correct + # namespace, where they can be more modularly isolated and ownership is clear. + # + # @example + # # bad + # # path: components/my_component/app/controllers/foo_controller.rb + # class FooController < ApplicationController + # # ... + # end + # + # # good + # # path: components/my_component/app/controllers/my_component/foo_controller.rb + # module MyComponent + # class FooController < MyComponent::ApplicationController + # # ... + # end + # end + # + class ControllerFilePlacement < RuboCop::Cop::Cop + include FilePlacementHelp + + def investigate(processed_source) + return if processed_source.blank? + + path = processed_source.file_path + return unless applicable_component_path?(path, controllers_path) + + if path.include?(controller_concerns_path) + return if namespaced_correctly?(path, controller_concerns_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, controller_concerns_path)) + end + return if namespaced_correctly?(path, controllers_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, controllers_path)) + end + + private + + def controllers_path + "app/controllers/" + end + + def controller_concerns_path + "app/controllers/concerns/" + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/dependency_version.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/dependency_version.rb new file mode 100644 index 00000000..4909efb7 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/dependency_version.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + class DependencyVersion < RuboCop::Cop::Cop + extend NodePattern::Macros + + MSG = "External component dependencies should be declared with a version" + + def investigate(processed_source) + return if processed_source.blank? + + path = processed_source.file_path + return unless path.end_with?(".gemspec") + + dependency_declarations(processed_source.ast).each do |dep| + next if declares_version?(dep) + + add_offense(dep, message: MSG) + end + end + + private + + def_node_search :dependency_declarations, <<~PATTERN + (send (lvar _) {:add_dependency :add_runtime_dependency :add_development_dependency} (str _) ...) + PATTERN + + def declares_version?(node) + node.first_argument != node.last_argument + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/file_placement_help.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/file_placement_help.rb new file mode 100644 index 00000000..c263641c --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/file_placement_help.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + # Methods that help analyzing file placement within Nitro components + module FilePlacementHelp + FILE_PLACEMENT_MSG = + "Do not add top-level files into `%s`. " \ + "Namespace them like `%s`" + + def applicable_component_path?(path, matcher) + in_a_component?(path) && path_contains_matcher?(path, matcher) + end + + def namespaced_correctly?(path, matcher) + potential_component_name = component_name(path, matcher) + component_path = File.join( + potential_component_name, + matcher, + potential_component_name + ) + path.include?("#{component_path}/") || path.include?("#{component_path}.rb") + end + + def file_placement_msg(path, matcher) + format(FILE_PLACEMENT_MSG, + matcher_path: matcher, + correct_path: correct_path(path, matcher)) + end + + private + + def correct_path(path, matcher) + file = path.split(matcher).last + "#{matcher}#{component_name(path, matcher)}/#{file}" + end + + def component_name(path, matcher) + path.split(matcher).first.split("/").last + end + + def in_a_component?(path) + path.include?("components/") + end + + def path_contains_matcher?(path, matcher) + path.include?(matcher) + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/gem_requirement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/gem_requirement.rb new file mode 100644 index 00000000..6e641d80 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/gem_requirement.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + class GemRequirement < RuboCop::Cop::Cop + MSG = "Component Gemfile dependencies must specify " \ + "'require: nil'." + + def investigate(processed_source) + return if processed_source.blank? + + gem_block = component_gem_block(processed_source.ast)&.first + return unless gem_block + + process_component_declarations(gem_block) + end + + private + + def process_component_declarations(gem_block) + if gem_block.send_type? + add_gem_offenses(gem_block) + else + gem_listings(gem_block).each do |gem_node| + add_gem_offenses(gem_node) + end + end + end + + def add_gem_offenses(gem_node) + component_options = gem_options(gem_node).first + return if component_options && not_required?(component_options) + + add_offense(gem_node, message: MSG) + end + + def_node_matcher :component_gem_block, <<~PATTERN + (:begin ... + (:block + (:send nil? :path (:str "..")) + (:args) + $... + ) + ) + PATTERN + + def_node_matcher :gem_options, "(:send nil? :gem _ $...)" + def_node_matcher :gem_listings, "(:begin $...)" + + def_node_matcher :not_required?, <<~PATTERN + (:hash + (:pair + (:sym :require) + (${nil false}) + ) + ) + PATTERN + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/helper_file_placement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/helper_file_placement.rb new file mode 100644 index 00000000..b8db13c3 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/helper_file_placement.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + # This cop disallows adding global helpers to the `app/helpers` directory. + # + # The goal is to encourage developers to put new helpers inside the correct + # namespace, where they can be more modularly isolated and ownership is clear. + # + # @example + # # bad + # # path: components/my_component/app/helpers/foo.rb + # class Foo + # # ... + # end + # + # # good + # # path: components/my_component/app/helpers/my_component/foo.rb + # module MyComponent + # class Foo + # # ... + # end + # end + # + class HelperFilePlacement < RuboCop::Cop::Cop + include FilePlacementHelp + + def investigate(processed_source) + return if processed_source.blank? + + path = processed_source.file_path + return unless applicable_component_path?(path, helpers_path) + return if namespaced_correctly?(path, helpers_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, helpers_path)) + end + + private + + def helpers_path + "app/helpers/" + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/inheritance.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/inheritance.rb new file mode 100644 index 00000000..26f15caa --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/inheritance.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + class Inheritance < RuboCop::Cop::Cop + PROTECTED_GLOBAL_CONSTANTS = %w[ + ApplicationController + ApplicationRecord + ApiController + ].freeze + + MSG = "Do not directly inherit from a global %s. " \ + "Instead, inherit from your component's modularized " \ + "%s, such as MyComponent::%s." + + def on_class(node) + inheritance_constant = node.node_parts[1] + inheritance_class = inheritance_constant&.source + return unless PROTECTED_GLOBAL_CONSTANTS.include?(inheritance_class) + + add_offense(inheritance_constant, + message: format(MSG, class: inheritance_class)) + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/job_file_placement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/job_file_placement.rb new file mode 100644 index 00000000..2e42b809 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/job_file_placement.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + # This cop disallows adding global jobs to the `app/jobs` directory. + # + # The goal is to encourage developers to put new jobs inside the correct + # namespace, where they can be more modularly isolated and ownership is clear. + # + # @example + # # bad + # # path: components/my_component/app/jobs/foo_job.rb + # class FooJob + # # ... + # end + # + # # good + # # path: components/my_component/app/jobs/my_component/foo_job.rb + # module MyComponent + # class FooJob + # # ... + # end + # end + # + class JobFilePlacement < RuboCop::Cop::Cop + include FilePlacementHelp + + def investigate(processed_source) + return if processed_source.blank? + + path = processed_source.file_path + return unless applicable_component_path?(path, jobs_path) + return if namespaced_correctly?(path, jobs_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, jobs_path)) + end + + private + + def jobs_path + "app/jobs/" + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/lib_file_placement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/lib_file_placement.rb new file mode 100644 index 00000000..e15f5001 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/lib_file_placement.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + # This cop disallows adding library files directly into the `lib/` directory. + # + # The goal is to encourage developers to put new library files inside the correct + # namespace, where they can be more modularly isolated and ownership is clear. + # + # Exceptions to this rule are `spec/lib/*` and `lib/tasks/*` file patterns. + # + # @example + # # bad + # # path: components/my_component/lib/foo.rb + # class Foo + # # ... + # end + # + # # good + # # path: components/my_component/lib/my_component/foo.rb + # module MyComponent + # class Foo + # # ... + # end + # end + # + class LibFilePlacement < RuboCop::Cop::Cop + include FilePlacementHelp + + def investigate(processed_source) + return if processed_source.blank? + + path = processed_source.file_path + return unless applicable_component_path?(path, lib_path) + return if acceptable_lib_path?(path) || namespaced_correctly?(path, lib_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, lib_path)) + end + + private + + def acceptable_lib_path?(path) + path.include?("lib/tasks/") || path.include?("spec/lib/") + end + + def lib_path + "lib/" + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/mailer_file_placement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/mailer_file_placement.rb new file mode 100644 index 00000000..877107cf --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/mailer_file_placement.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + # This cop disallows adding global helpers to the `app/mailers` directory. + # + # The goal is to encourage developers to put new mailer files inside the correct + # namespace, where they can be more modularly isolated and ownership is clear. + # + # @example + # # bad + # # path: components/my_component/app/mailers/foo.rb + # class Foo + # # ... + # end + # + # # good + # # path: components/my_component/app/mailers/my_component/foo.rb + # module MyComponent + # class Foo + # # ... + # end + # end + # + class MailerFilePlacement < RuboCop::Cop::Cop + include FilePlacementHelp + + def investigate(processed_source) + return if processed_source.blank? + + path = processed_source.file_path + return unless applicable_component_path?(path, mailers_path) + return if namespaced_correctly?(path, mailers_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, mailers_path)) + end + + private + + def mailers_path + "app/mailers/" + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/model_file_placement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/model_file_placement.rb new file mode 100644 index 00000000..308c4682 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/model_file_placement.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + # This cop disallows adding global models to the `app/models` directory. + # + # The goal is to encourage developers to put new models inside the correct + # namespace, where they can be more modularly isolated and ownership is clear. + # + # @example + # # bad + # # path: components/my_component/app/models/foo.rb + # class Foo < ApplicationRecord + # # ... + # end + # + # # good + # # path: components/my_component/app/models/my_component/foo.rb + # module MyComponent + # class Foo < MyComponent::ApplicationRecord + # # ... + # end + # end + # + class ModelFilePlacement < RuboCop::Cop::Cop + include FilePlacementHelp + + def investigate(processed_source) + return if processed_source.blank? + + path = processed_source.file_path + return unless applicable_component_path?(path, models_path) + + if path.include?(model_concerns_path) + return if namespaced_correctly?(path, model_concerns_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, model_concerns_path)) + end + return if namespaced_correctly?(path, models_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, models_path)) + end + + private + + def models_path + "app/models/" + end + + def model_concerns_path + "app/models/concerns/" + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/presenter_file_placement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/presenter_file_placement.rb new file mode 100644 index 00000000..846da02b --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/presenter_file_placement.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + # This cop disallows adding global presenters to the `app/presenters` directory. + # + # The goal is to encourage developers to put new presenters inside the correct + # namespace, where they can be more modularly isolated and ownership is clear. + # + # @example + # # bad + # # path: components/my_component/app/presenters/foo_presenter.rb + # class FooPresenter + # # ... + # end + # + # # good + # # path: components/my_component/app/presenters/my_component/foo_presenter.rb + # module MyComponent + # class FooPresenter + # # ... + # end + # end + # + class PresenterFilePlacement < RuboCop::Cop::Cop + include FilePlacementHelp + + def investigate(processed_source) + return if processed_source.blank? + + path = processed_source.file_path + return unless applicable_component_path?(path, presenters_path) + return if namespaced_correctly?(path, presenters_path) + + add_offense(processed_source.ast, + message: file_placement_msg(path, presenters_path)) + end + + private + + def presenters_path + "app/presenters/" + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra/view_component_file_placement.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra/view_component_file_placement.rb new file mode 100644 index 00000000..d645cdf9 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra/view_component_file_placement.rb @@ -0,0 +1,100 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + # This cop disallows adding global view_components to the `app/components` directory. + # + # The goal is to encourage developers to put new view_components inside the correct + # namespace, where they can be more modularly isolated and ownership is clear. + # + # The correct namespace is `app/components/my_component/resource/view_component.rb. + # Similar to how `app/views` templates are nested in a directory named after the controller's resource. + # + # @example + # # bad + # # path: components/my_component/app/components/foo_component.rb + # class FooComponent < ::ViewComponent::Base + # # ... + # end + # + # # bad + # # path: components/my_component/app/components/my_component/foo_component.rb + # module MyComponent + # class FooComponent < MyComponent::ApplicationComponent + # # ... + # end + # end + # + # # acceptable + # # path: components/my_component/app/components/my_component/application_component.rb + # module MyComponent + # class ApplicationComponent < ::ViewComponent::Base + # # ... + # end + # end + # end + # + # # good + # # path: components/my_component/app/components/my_component/resource/foo_component.rb + # module MyComponent + # module Resource + # class FooComponent < MyComponent::ApplicationComponent + # # ... + # end + # end + # end + # + class ViewComponentFilePlacement < RuboCop::Cop::Cop + FILE_PLACEMENT_MSG = + "Nest ViewComponent definitions in the parent component and resource namespace. " \ + "For example: `%s`" + + def investigate(processed_source) + return if processed_source.blank? + return unless path_contains_matcher? + return if namespaced_correctly? + + add_offense(processed_source.ast, + message: format(FILE_PLACEMENT_MSG, correct_path: correct_path)) + end + + private + + def view_components_path + "app/components/" + end + + def path + @path ||= processed_source.file_path + end + + def namespaced_correctly? + potential_component_name = component_name + component_path = File.join( + potential_component_name, + view_components_path, + potential_component_name + ) + return false unless path.include?("#{component_path}/") + + sub_path = path.split("#{component_path}/").last + sub_path.include?("/") || sub_path == "application_component.rb" + end + + def correct_path + file = path.split("/").last + "#{view_components_path}#{component_name}//#{file}" + end + + def component_name + path.split(view_components_path).first.split("/").last + end + + def path_contains_matcher? + path.include?(view_components_path) + end + end + end + end +end diff --git a/packages/rubocop-cobra/lib/rubocop/cop/cobra_cops.rb b/packages/rubocop-cobra/lib/rubocop/cop/cobra_cops.rb new file mode 100644 index 00000000..5d850152 --- /dev/null +++ b/packages/rubocop-cobra/lib/rubocop/cop/cobra_cops.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Cobra + require_relative "cobra/file_placement_help" + + require_relative "cobra/command_file_placement" + require_relative "cobra/controller_file_placement" + require_relative "cobra/dependency_version" + require_relative "cobra/gem_requirement" + require_relative "cobra/helper_file_placement" + require_relative "cobra/inheritance" + require_relative "cobra/job_file_placement" + require_relative "cobra/lib_file_placement" + require_relative "cobra/mailer_file_placement" + require_relative "cobra/model_file_placement" + require_relative "cobra/presenter_file_placement" + require_relative "cobra/view_component_file_placement" + end + end +end diff --git a/packages/rubocop-cobra/mkdocs.yml b/packages/rubocop-cobra/mkdocs.yml new file mode 100644 index 00000000..e19c41a4 --- /dev/null +++ b/packages/rubocop-cobra/mkdocs.yml @@ -0,0 +1,9 @@ +site_name: Rubocop Cobra +site_description: Gem focused on providing Cops to support a healthy cobra app development +repo_url: https://github.com/powerhome/power_linting +edit_uri: edit/main/rubocop_cobra/docs/ +nav: + - 'Home': 'README.md' + +plugins: + - techdocs-core diff --git a/packages/rubocop-cobra/rubocop-cobra.gemspec b/packages/rubocop-cobra/rubocop-cobra.gemspec new file mode 100644 index 00000000..84667195 --- /dev/null +++ b/packages/rubocop-cobra/rubocop-cobra.gemspec @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require_relative "lib/rubocop/cobra/version" + +Gem::Specification.new do |spec| + spec.name = "rubocop-cobra" + spec.version = RuboCop::Cobra::VERSION + spec.authors = ["Carlos Palhares", "Garett Arrowood"] + spec.email = ["chjunior@gmail.com", "garettarrowood@gmail.com"] + + spec.summary = "Cobra rubocop linters" + spec.description = "Cobra rubocop linters" + spec.homepage = "https://github.com/powerhome/power_linting" + spec.license = "MIT" + spec.required_ruby_version = ">= 2.7.0" + + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = spec.homepage + spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md" + + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + spec.files = Dir.chdir(File.expand_path(__dir__)) do + `git ls-files -z`.split("\x0").reject do |f| + (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + # Uncomment to register a new dependency of your gem + # spec.add_dependency "example-gem", "~> 1.0" + + # For more information and examples about making a new gem, check out our + # guide at: https://bundler.io/guides/creating_gem.html + + spec.add_runtime_dependency "rubocop" + spec.add_runtime_dependency "rubocop-powerhome" + spec.metadata["rubygems_mfa_required"] = "true" + + spec.add_development_dependency "license_finder", "~> 7.0" + spec.add_development_dependency "pry-byebug", "3.9.0" +end diff --git a/packages/rubocop-cobra/sig/rubocop/cobra.rbs b/packages/rubocop-cobra/sig/rubocop/cobra.rbs new file mode 100644 index 00000000..8a7e75d5 --- /dev/null +++ b/packages/rubocop-cobra/sig/rubocop/cobra.rbs @@ -0,0 +1,6 @@ +module Rubocop + module Cobra + VERSION: String + # See the writing guide of rbs: https://github.com/ruby/rbs#guides + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cobra_spec.rb b/packages/rubocop-cobra/spec/rubocop/cobra_spec.rb new file mode 100644 index 00000000..4bf9a167 --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cobra_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cobra do + it "has a version number" do + expect(RuboCop::Cobra::VERSION).not_to be nil + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/command_file_placement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/command_file_placement_spec.rb new file mode 100644 index 00000000..235f1ac5 --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/command_file_placement_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::CommandFilePlacement do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when linting a file not in app/commands/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + + it "when command file is correctly namespaced" do + file_path = "root/components/my_component/app/commands/my_component/foo.rb" + + expect_no_offenses(source, file_path) + end + end + + context "registers an offense" do + it "when command is defined directly inside app/commands/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/commands/`. Namespace them like `app/commands/my_component/foo.rb` + end + RUBY + + file_path = "components/my_component/app/commands/foo.rb" + + expect_offense(source, file_path) + end + + it "when command is defined inside a different subdirectory of app/commands/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/commands/`. Namespace them like `app/commands/my_component/other_namespace/foo.rb` + end + RUBY + + file_path = "components/my_component/app/commands/other_namespace/foo.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/controller_file_placement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/controller_file_placement_spec.rb new file mode 100644 index 00000000..f9e96212 --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/controller_file_placement_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::ControllerFilePlacement do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when linting a file not in app/controllers/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + + it "when controller is correctly namespaced" do + file_path = "root/components/my_component/app/controllers/my_component/foo_controller.rb" + + expect_no_offenses(source, file_path) + end + + it "when controller is correctly namespaced with concerns" do + file_path = "root/components/my_component/app/controllers/concerns/my_component/foo.rb" + + expect_no_offenses(source, file_path) + end + end + + context "registers an offense" do + it "when controller is defined directly inside app/controllers/" do + source = <<~RUBY + class FooController + ^^^^^^^^^^^^^^^^^^^ Do not add top-level files into `app/controllers/`. Namespace them like `app/controllers/my_component/foo_controller.rb` + end + RUBY + + file_path = "components/my_component/app/controllers/foo_controller.rb" + + expect_offense(source, file_path) + end + + it "when controller is defined inside a different subdirectory of app/controllers/" do + source = <<~RUBY + class FooController + ^^^^^^^^^^^^^^^^^^^ Do not add top-level files into `app/controllers/`. Namespace them like `app/controllers/my_component/other_namespace/foo_controller.rb` + end + RUBY + + file_path = "components/my_component/app/controllers/other_namespace/foo_controller.rb" + + expect_offense(source, file_path) + end + + it "when file is directly inside a concerns directory inside app/controllers/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/controllers/concerns/`. Namespace them like `app/controllers/concerns/my_component/foo.rb` + end + RUBY + + file_path = "components/my_component/app/controllers/concerns/foo.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/dependency_version.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/dependency_version.rb new file mode 100644 index 00000000..77bc260e --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/dependency_version.rb @@ -0,0 +1,128 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::DependencyVersion do + subject(:cop) { described_class.new } + + before { allow(cop).to receive(:nitro_components).and_return(["nitro_component"]) } + + context "#add_dependency" do + context "registers offense" do + it "when a dependency is declared without a version" do + source = <<~RUBY + Gem::Specification.new do |s| + s.add_dependency "outside_lib" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ External component dependencies should be declared with a version + end + RUBY + + file_path = "/components/my_component/my_component.gemspec" + + expect_offense(source, file_path) + end + end + + context "does not register offenses" do + it "when dependency is versioned" do + source = <<~RUBY + Gem::Specification.new do |s| + s.add_dependency "some_lib", "1.0.1" + end + RUBY + + file_path = "/components/my_component/my_component.gemspec" + + expect_no_offenses(source, file_path) + end + end + end + + context "#add_development_dependency" do + context "registers offense" do + it "when an external dependency is declared without a version" do + source = <<~RUBY + Gem::Specification.new do |s| + s.add_development_dependency "outside_lib" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ External component dependencies should be declared with a version + end + RUBY + + file_path = "/components/my_component/my_component.gemspec" + + expect_offense(source, file_path) + end + end + + context "does not register offenses" do + it "when external dependency is versioned" do + source = <<~RUBY + Gem::Specification.new do |s| + s.add_development_dependency "some_lib", "4.3.56" + end + RUBY + + file_path = "/components/my_component/my_component.gemspec" + + expect_no_offenses(source, file_path) + end + end + end + + context "#add_runtime_dependency" do + context "registers offense" do + it "when an external dependency is declared without a version" do + source = <<~RUBY + Gem::Specification.new do |s| + s.add_runtime_dependency "some_lib" + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ External component dependencies should be declared with a version + end + RUBY + + file_path = "/components/my_component/my_component.gemspec" + + expect_offense(source, file_path) + end + end + + context "does not register offenses" do + it "when external dependency is versioned" do + source = <<~RUBY + Gem::Specification.new do |s| + s.add_runtime_dependency "some_lib", "1.6.3" + end + RUBY + + file_path = "/components/my_component/my_component.gemspec" + + expect_no_offenses(source, file_path) + end + end + end + + context "all dependency methods" do + context "do not register offenses" do + it "when file does not end in .gemspec" do + source = <<~RUBY + Gem::Specification.new do |s| + s.add_dependency "some_lib" + end + RUBY + + file_path = "/components/my_component/my_component.anything" + + expect_no_offenses(source, file_path) + end + + it "when not invoked within a block" do + source = <<~RUBY + s.add_development_dependency "some_lib" + RUBY + + file_path = "/components/my_component/my_component.gemspec" + + expect_no_offenses(source, file_path) + end + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/gem_requirement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/gem_requirement_spec.rb new file mode 100644 index 00000000..e8e1d6b9 --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/gem_requirement_spec.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::GemRequirement do + subject(:cop) { described_class.new } + + it "accepts component gem dependencies that specify required: nil" do + expect_no_offenses(<<~RUBY) + source "https://rubygems.org" + + path ".." do + gem "nitro_component", require: nil + end + RUBY + end + + it "accepts component gem dependencies that specify required: false" do + expect_no_offenses(<<~RUBY) + source "https://rubygems.org" + + path ".." do + gem "nitro_component", require: false + end + RUBY + end + + it "ignores non-component gem dependencies" do + expect_no_offenses(<<~RUBY) + source "https://rubygems.org" + + gem "foo" + RUBY + end + + it "accepts valid component gem dependencies mixed with Ruby comments" do + expect_no_offenses(<<~RUBY) + source "https://rubygems.org" + + path ".." do + # Dependencies on other components go here + gem "nitro_component", require: nil + end + RUBY + end + + it "accepts valid component gem dependencies using old hash syntax" do + expect_no_offenses(<<~RUBY) + source "https://rubygems.org" + + path ".." do + gem "nitro_component", :require => nil + end + RUBY + end + + context "registers an offense for component gem dependencies that are required" do + it "when explicitly specified" do + expect_offense(<<~RUBY) + source "https://rubygems.org" + + path ".." do + gem "nitro_component", require: true + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Component Gemfile dependencies must specify 'require: nil'. + end + RUBY + end + + it "when not explicitly specified" do + expect_offense(<<~RUBY) + source "https://rubygems.org" + + path ".." do + gem "nitro_component" + ^^^^^^^^^^^^^^^^^^^^^ Component Gemfile dependencies must specify 'require: nil'. + end + RUBY + end + + it "when mixed with valid declarations" do + expect_offense(<<~RUBY) + source "https://rubygems.org" + + path ".." do + # Dependencies on other components go here + gem "nitro_component", require: nil + gem "other_component" + ^^^^^^^^^^^^^^^^^^^^^ Component Gemfile dependencies must specify 'require: nil'. + gem "another_component", require: nil + end + RUBY + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/helper_file_placement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/helper_file_placement_spec.rb new file mode 100644 index 00000000..a61eefa7 --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/helper_file_placement_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::HelperFilePlacement do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when linting a file not in app/helpers/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + + it "when helper is correctly namespaced" do + file_path = "root/components/my_component/app/helpers/my_component/foo.rb" + + expect_no_offenses(source, file_path) + end + end + + context "registers an offense" do + it "when helper is defined directly inside app/helpers/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/helpers/`. Namespace them like `app/helpers/my_component/foo.rb` + end + RUBY + + file_path = "components/my_component/app/helpers/foo.rb" + + expect_offense(source, file_path) + end + + it "when helper is defined inside a different subdirectory of app/helpers/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/helpers/`. Namespace them like `app/helpers/my_component/other_namespace/foo.rb` + end + RUBY + + file_path = "components/my_component/app/helpers/other_namespace/foo.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/inheritance_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/inheritance_spec.rb new file mode 100644 index 00000000..b757ee1c --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/inheritance_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::Inheritance do + subject(:cop) { described_class.new } + + it "accepts modularized ApplicationController inheritance" do + expect_no_offenses(<<~RUBY) + class FooController < MyComponent::ApplicationController + end + RUBY + end + + it "registers an offense when inheriting from ApplicationController" do + expect_offense(<<-RUBY) + class FooController < ApplicationController + ^^^^^^^^^^^^^^^^^^^^^ Do not directly inherit from a global ApplicationController. Instead, inherit from your component's modularized ApplicationController, such as MyComponent::ApplicationController. + end + RUBY + end + + it "accepts modularized ApplicationRecord inheritance" do + expect_no_offenses(<<~RUBY) + class Foo < MyComponent::ApplicationRecord + end + RUBY + end + + it "registers an offense when inheriting from ApplicationRecord" do + expect_offense(<<-RUBY) + class Foo < ApplicationRecord + ^^^^^^^^^^^^^^^^^ Do not directly inherit from a global ApplicationRecord. Instead, inherit from your component's modularized ApplicationRecord, such as MyComponent::ApplicationRecord. + end + RUBY + end + + it "accepts modularized ApiController inheritance" do + expect_no_offenses(<<~RUBY) + class FooController < MyComponent::ApiController + end + RUBY + end + + it "registers an offense when inheriting from ApiController" do + expect_offense(<<-RUBY) + class FooController < ApiController + ^^^^^^^^^^^^^ Do not directly inherit from a global ApiController. Instead, inherit from your component's modularized ApiController, such as MyComponent::ApiController. + end + RUBY + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/job_file_placement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/job_file_placement_spec.rb new file mode 100644 index 00000000..1dc3b4d6 --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/job_file_placement_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::JobFilePlacement do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when linting a file not in app/jobs/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + + it "when job is correctly namespaced" do + file_path = "root/components/my_component/app/jobs/my_component/foo_job.rb" + + expect_no_offenses(source, file_path) + end + end + + context "registers an offense" do + it "when job is defined directly inside app/jobs/" do + source = <<~RUBY + class FooJob + ^^^^^^^^^^^^ Do not add top-level files into `app/jobs/`. Namespace them like `app/jobs/my_component/foo_job.rb` + end + RUBY + + file_path = "components/my_component/app/jobs/foo_job.rb" + + expect_offense(source, file_path) + end + + it "when job is defined directly inside mismatched subdirectory of app/jobs/" do + source = <<~RUBY + class FooJob + ^^^^^^^^^^^^ Do not add top-level files into `app/jobs/`. Namespace them like `app/jobs/my_component/other_namespace/foo_job.rb` + end + RUBY + + file_path = "components/my_component/app/jobs/other_namespace/foo_job.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/lib_file_placement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/lib_file_placement_spec.rb new file mode 100644 index 00000000..65250629 --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/lib_file_placement_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::LibFilePlacement do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when file is not in lib/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + + it "when file is correctly namespaced" do + file_path = "root/components/my_component/lib/my_component/foo.rb" + + expect_no_offenses(source, file_path) + end + + it "when file is in lib/tasks/" do + file_path = "components/my_component/lib/tasks/foo.rb" + + expect_no_offenses(source, file_path) + end + + it "when file is the name of the component" do + file_path = "components/my_component/lib/my_component.rb" + + expect_no_offenses(source, file_path) + end + + it "when lib directory is inside the spec directory" do + file_path = "components/my_component/spec/lib/foo_spec.rb" + + expect_no_offenses(source, file_path) + end + + it "when file is not in a component" do + file_path = "nitro-web/lib/foo.rb" + + expect_no_offenses(source, file_path) + end + end + + context "registers an offense" do + it "when lib file is defined directly inside lib/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `lib/`. Namespace them like `lib/awesome_component/foo.rb` + end + RUBY + + file_path = "components/awesome_component/lib/foo.rb" + + expect_offense(source, file_path) + end + + it "when lib file is defined inside a different subdirectory of lib/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `lib/`. Namespace them like `lib/my_component/other_namespace/my_file.rb` + end + RUBY + + file_path = "components/my_component/lib/other_namespace/my_file.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/mailer_file_placement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/mailer_file_placement_spec.rb new file mode 100644 index 00000000..fd75c7f8 --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/mailer_file_placement_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::MailerFilePlacement do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when linting a file not in app/mailers/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + + it "when mailer file is correctly namespaced" do + file_path = "root/components/my_component/app/mailers/my_component/foo.rb" + + expect_no_offenses(source, file_path) + end + end + + context "registers an offense" do + it "when mailer is defined directly inside app/mailers/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/mailers/`. Namespace them like `app/mailers/my_component/foo.rb` + end + RUBY + + file_path = "components/my_component/app/mailers/foo.rb" + + expect_offense(source, file_path) + end + + it "when mailer is defined inside a different subdirectory of app/mailers/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/mailers/`. Namespace them like `app/mailers/my_component/other_namespace/foo.rb` + end + RUBY + + file_path = "components/my_component/app/mailers/other_namespace/foo.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/model_file_placement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/model_file_placement_spec.rb new file mode 100644 index 00000000..e077703e --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/model_file_placement_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::ModelFilePlacement do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when linting a file not in app/models/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + + it "when model is correctly namespaced" do + file_path = "root/components/my_component/app/models/my_component/foo.rb" + + expect_no_offenses(source, file_path) + end + + it "when model is correctly namespaced with concerns" do + file_path = "root/components/my_component/app/models/concerns/my_component/foo.rb" + + expect_no_offenses(source, file_path) + end + end + + context "registers an offense" do + it "when model is defined directly inside app/models/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/models/`. Namespace them like `app/models/my_component/foo.rb` + end + RUBY + + file_path = "components/my_component/app/models/foo.rb" + + expect_offense(source, file_path) + end + + it "when model is defined directly inside mismatched subdirectory of app/models/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/models/`. Namespace them like `app/models/my_component/other_namespace/foo.rb` + end + RUBY + + file_path = "components/my_component/app/models/other_namespace/foo.rb" + + expect_offense(source, file_path) + end + + it "when file is directly inside a concerns directory inside of app/models/" do + source = <<~RUBY + class Foo + ^^^^^^^^^ Do not add top-level files into `app/models/concerns/`. Namespace them like `app/models/concerns/my_component/foo.rb` + end + RUBY + + file_path = "components/my_component/app/models/concerns/foo.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/presenter_file_placement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/presenter_file_placement_spec.rb new file mode 100644 index 00000000..9185e14e --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/presenter_file_placement_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::PresenterFilePlacement do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when linting a file not in app/presenters/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + + it "when presenter is correctly namespaced" do + file_path = "root/components/my_component/app/presenters/my_component/foo_presenter.rb" + + expect_no_offenses(source, file_path) + end + end + + context "registers an offense" do + it "when presenter is defined directly inside app/presenters/" do + source = <<~RUBY + class FooPresenter + ^^^^^^^^^^^^^^^^^^ Do not add top-level files into `app/presenters/`. Namespace them like `app/presenters/my_component/foo_presenter.rb` + end + RUBY + + file_path = "components/my_component/app/presenters/foo_presenter.rb" + + expect_offense(source, file_path) + end + + it "when presenter is defined directly inside mismatched subdirectory of app/presenters/" do + source = <<~RUBY + class FooPresenter + ^^^^^^^^^^^^^^^^^^ Do not add top-level files into `app/presenters/`. Namespace them like `app/presenters/my_component/other_namespace/foo_presenter.rb` + end + RUBY + + file_path = "components/my_component/app/presenters/other_namespace/foo_presenter.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-cobra/spec/rubocop/cop/cobra/view_component_file_placement_spec.rb b/packages/rubocop-cobra/spec/rubocop/cop/cobra/view_component_file_placement_spec.rb new file mode 100644 index 00000000..96f57072 --- /dev/null +++ b/packages/rubocop-cobra/spec/rubocop/cop/cobra/view_component_file_placement_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Cobra::ViewComponentFilePlacement do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when linting a file not in app/components/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + + it "when view_component is correctly namespaced" do + file_path = "root/components/my_component/app/components/my_component/resource/foo_component.rb" + + expect_no_offenses(source, file_path) + end + + it "when application_component is correctly namespaced" do + file_path = "root/components/my_component/app/components/my_component/application_component.rb" + + expect_no_offenses(source, file_path) + end + end + + context "registers an offense" do + it "when view_component is defined directly inside app/components/" do + source = <<~RUBY + class FooComponent < ::ViewComponent::Base + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Nest ViewComponent definitions in the parent component and resource namespace. For example: `app/components/my_component//foo_component.rb` + end + RUBY + + file_path = "components/my_component/app/components/foo_component.rb" + + expect_offense(source, file_path) + end + + it "when view_component is defined directly inside mismatched subdirectory of app/components/" do + source = <<~RUBY + class FooComponent < ::ViewComponent::Base + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Nest ViewComponent definitions in the parent component and resource namespace. For example: `app/components/my_component//foo_component.rb` + end + RUBY + + file_path = "components/my_component/app/components/other_namespace/resource/foo_component.rb" + + expect_offense(source, file_path) + end + + it "when view_component is defined directly inside mismatched subdirectory of app/components/" do + source = <<~RUBY + class FooComponent < ::ViewComponent::Base + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Nest ViewComponent definitions in the parent component and resource namespace. For example: `app/components/my_component//foo_component.rb` + end + RUBY + + file_path = "components/my_component/app/components/other_namespace/resource/foo_component.rb" + + expect_offense(source, file_path) + end + + it "when view_component is defined within directory of component name, but not in an additional subdirectory" do + source = <<~RUBY + module MyComponent + ^^^^^^^^^^^^^^^^^^ Nest ViewComponent definitions in the parent component and resource namespace. For example: `app/components/my_component//foo_component.rb` + class FooComponent < MyComponent::ApplicationComponent + end + end + RUBY + + file_path = "components/my_component/app/components/my_component/foo_component.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-cobra/spec/spec_helper.rb b/packages/rubocop-cobra/spec/spec_helper.rb new file mode 100644 index 00000000..3683faf8 --- /dev/null +++ b/packages/rubocop-cobra/spec/spec_helper.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require "rubocop-cobra" +require "pry-byebug" + +require "rubocop/rspec/support" + +RSpec.configure do |config| + config.include RuboCop::RSpec::ExpectOffense + + config.disable_monkey_patching! + config.raise_errors_for_deprecations! + config.raise_on_warning = true + config.fail_if_no_examples = true + + config.order = :random + Kernel.srand config.seed +end diff --git a/packages/rubocop-powerhome/.gitignore b/packages/rubocop-powerhome/.gitignore new file mode 100644 index 00000000..9cfda195 --- /dev/null +++ b/packages/rubocop-powerhome/.gitignore @@ -0,0 +1,11 @@ +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/pkg/ +/spec/reports/ +/tmp/ + +# rspec failure tracking +.rspec_status +Gemfile.lock diff --git a/packages/rubocop-powerhome/.rubocop.yml b/packages/rubocop-powerhome/.rubocop.yml new file mode 100644 index 00000000..8d0341e3 --- /dev/null +++ b/packages/rubocop-powerhome/.rubocop.yml @@ -0,0 +1,14 @@ +require: + - rubocop-powerhome + +Naming/FileName: + Exclude: + - lib/rubocop-powerhome.rb + +Metrics/BlockLength: + Exclude: + - 'spec/**/*' + - 'rubocop-powerhome.gemspec' + +Rails: + Enabled: false diff --git a/packages/rubocop-powerhome/CHANGELOG.md b/packages/rubocop-powerhome/CHANGELOG.md new file mode 100644 index 00000000..21d84cdb --- /dev/null +++ b/packages/rubocop-powerhome/CHANGELOG.md @@ -0,0 +1,37 @@ +## [0.5.0] - 2022-07-22 + +### Features + +- Provide style guide references and helpful hints on violations. (#36) +- Ignore Metrics/BlockLength on Rspec's context and describe (#43) + +### Documentation +- Fix rel links in README (#37) +- Initial portal setup (#34) + +### Updates +- Lock file maintenance +- Update tj-actions/changed-files action to v24 (#47) +- Update dependency rubocop to ~> 1.32.0 (#46) +- Update dependency babel-eslint to v10 (#45) +- Update all non-major dependencies (#44) +- Update typescript-eslint monorepo to v5 (major) (#24) +- Update dependency eslint-webpack-plugin to v3 (#23) +- Update dependency eslint-plugin-jsx-control-statements to v3 (#22) +- Update dependency eslint-plugin-flowtype to v8 (#21) +- Update dependency babel-eslint to v10 (#19) +- Update all non-major dependencies (#16) +- Pin dependency babel-eslint to v (#15) + +## [0.4.1] - 2022-06-02 + +- Fix bug in Naming/ViewComponent when class does not inherit + +## [0.4.0] - 2022-06-01 + +- Adds Naming/ViewComponent cop +- Adds Style/NoHelpers cop + +## [0.1.0] - 2022-05-18 + +- Initial release diff --git a/packages/rubocop-powerhome/Gemfile b/packages/rubocop-powerhome/Gemfile new file mode 100644 index 00000000..335fe68e --- /dev/null +++ b/packages/rubocop-powerhome/Gemfile @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +# Specify your gem's dependencies in rubocop-powerhome.gemspec +gemspec + +rails_version = ENV.fetch("RAILS_VERSION", ">= 5.2.8.1") +gem "rails", rails_version diff --git a/packages/rubocop-powerhome/LICENSE.txt b/packages/rubocop-powerhome/LICENSE.txt new file mode 100644 index 00000000..fde926f5 --- /dev/null +++ b/packages/rubocop-powerhome/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright Power Home Remodeling Group, LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/rubocop-powerhome/Rakefile b/packages/rubocop-powerhome/Rakefile new file mode 100644 index 00000000..9709f0fd --- /dev/null +++ b/packages/rubocop-powerhome/Rakefile @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require "bundler/gem_tasks" + +require "rspec/core/rake_task" +RSpec::Core::RakeTask.new(:spec) + +require "rubocop/rake_task" +RuboCop::RakeTask.new(:rubocop) + +task default: %i[spec rubocop] + +desc "Generate a new cop with a template" +task :new_cop, [:cop] do |_task, args| + require "rubocop" + + cop_name = args.fetch(:cop) do + warn "usage: bundle exec rake new_cop[Department/Name]" + exit! + end + + generator = RuboCop::Cop::Generator.new(cop_name) + + generator.write_source + generator.write_spec + generator.inject_require(root_file_path: "lib/rubocop/cop/powerhome_cops.rb") + generator.inject_config(config_file_path: "config/default.yml") + + puts generator.todo +end diff --git a/packages/rubocop-powerhome/bin/console b/packages/rubocop-powerhome/bin/console new file mode 100755 index 00000000..95cca839 --- /dev/null +++ b/packages/rubocop-powerhome/bin/console @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "bundler/setup" +require "rubocop/powerhome" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# (If you use this, don't forget to add pry to your Gemfile!) +# require "pry" +# Pry.start + +require "irb" +IRB.start(__FILE__) diff --git a/packages/rubocop-powerhome/bin/rubocop b/packages/rubocop-powerhome/bin/rubocop new file mode 100755 index 00000000..d0c48829 --- /dev/null +++ b/packages/rubocop-powerhome/bin/rubocop @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'rubocop' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("rubocop", "rubocop") diff --git a/packages/rubocop-powerhome/bin/setup b/packages/rubocop-powerhome/bin/setup new file mode 100755 index 00000000..dce67d86 --- /dev/null +++ b/packages/rubocop-powerhome/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/packages/rubocop-powerhome/config/default.yml b/packages/rubocop-powerhome/config/default.yml new file mode 100644 index 00000000..6c25b533 --- /dev/null +++ b/packages/rubocop-powerhome/config/default.yml @@ -0,0 +1,95 @@ +AllCops: + TargetRubyVersion: 2.7 + NewCops: enable + DisplayStyleGuide: true + ExtraDetails: true + +Gemspec/RequiredRubyVersion: + Enabled: false + +Layout/AccessModifierIndentation: + EnforcedStyle: outdent + +Lint/OrAssignmentToConstant: + Enabled: false + +Lint/ScriptPermission: + Enabled: false + +Naming/MethodParameterName: + AllowedNames: + - io + - id + - to + - by + - 'on' + - in + - at + +Naming/ViewComponent: + Description: 'This cop requires ViewComponent classes to end with Component in their classname.' + Enabled: true + VersionAdded: '0.4.0' + +Rails: + Enabled: true + +# This was the rubocop default until Oct. 2019, when it was changed to slashes. +# This preserves the original setting. +Rails/FilePath: + EnforcedStyle: arguments + +Rails/HasManyOrHasOneDependent: + Enabled: false + +Rake: + Enabled: true + +RSpec: + Enabled: false + +RSpec/FactoryBot: + Enabled: true + +Style/Documentation: + Enabled: false + +Style/HashEachMethods: + Enabled: false + +Style/HashTransformKeys: + Enabled: false + +Style/HashTransformValues: + Enabled: false + +Style/Lambda: + EnforcedStyle: literal + +Style/NoHelpers: + Description: 'This cop blocks global helper modules from existing in an application.' + Enabled: true + VersionAdded: '0.4.0' + +Style/NumericPredicate: + Enabled: false + +Style/RescueStandardError: + EnforcedStyle: implicit + +# Single quotes being faster is hardly measurable and only affects parse time. +# Enforcing double quotes reduces the times where you need to change them when introducing an interpolation. +# Use single quotes only if their semantics are needed. +Style/StringLiterals: + EnforcedStyle: double_quotes + +Style/TrailingCommaInArrayLiteral: + EnforcedStyleForMultiline: comma + +Style/TrailingCommaInHashLiteral: + EnforcedStyleForMultiline: comma + +Metrics/BlockLength: + IgnoredMethods: + - describe + - context diff --git a/packages/rubocop-powerhome/doc/dependency_decisions.yml b/packages/rubocop-powerhome/doc/dependency_decisions.yml new file mode 100644 index 00000000..f734baa9 --- /dev/null +++ b/packages/rubocop-powerhome/doc/dependency_decisions.yml @@ -0,0 +1,3 @@ +--- +- - :inherit_from + - https://raw.githubusercontent.com/powerhome/oss-guide/master/license_rules.yml diff --git a/packages/rubocop-powerhome/docs/README.md b/packages/rubocop-powerhome/docs/README.md new file mode 100644 index 00000000..3df01ee8 --- /dev/null +++ b/packages/rubocop-powerhome/docs/README.md @@ -0,0 +1,42 @@ +# Rubocop::Powerhome + +This gem is focused on providing standard Rubocop configuration for Power Home Remodeling ruby apps. + +## Installation + +Add this line to your application's Gemfile under development: + +```ruby +gem "rubocop-powerhome", require: false +``` + +And then execute: + + $ bundle install + +## Usage + +Add a `require` line to your `.rubocop.yml`: + +```yml +require: + - rubocop-powerhome +``` + +That's it! You can override the standard configuration after that. + +It's recommended that you set `AllCops/TargetRubyVersion` in your project because some cops are Ruby version-dependent. See more [here](https://docs.rubocop.org/rubocop/configuration.html#setting-the-target-ruby-version). + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/powerhome/power_linting/rubocop-powerhome. + +## License + +The gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/packages/rubocop-powerhome/lib/rubocop-powerhome.rb b/packages/rubocop-powerhome/lib/rubocop-powerhome.rb new file mode 100644 index 00000000..82e53ce2 --- /dev/null +++ b/packages/rubocop-powerhome/lib/rubocop-powerhome.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require "rubocop" +require "rubocop-performance" +require "rubocop-rails" +require "rubocop-rake" +require "rubocop-rspec" + +require_relative "rubocop/powerhome" + +RuboCop::Powerhome::Inject.defaults! + +require_relative "rubocop/cop/naming_cops" +require_relative "rubocop/cop/style_cops" diff --git a/packages/rubocop-powerhome/lib/rubocop/cop/naming/view_component.rb b/packages/rubocop-powerhome/lib/rubocop/cop/naming/view_component.rb new file mode 100644 index 00000000..6b22b4ad --- /dev/null +++ b/packages/rubocop-powerhome/lib/rubocop/cop/naming/view_component.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Naming + # This cop requires ViewComponent classes to end with Component in their classname. + # + # @example + # # bad + # class Foo < ::ViewComponent::Base + # # ... + # end + # + # # good + # class FooComponent < ::ViewComponent::Base + # # ... + # end + # + class ViewComponent < RuboCop::Cop::Cop + def on_class(node) + inheritance_klass = node.node_parts[1]&.source + return unless view_component_class?(inheritance_klass) + + klass = node.node_parts[0]&.source + return if klass.end_with?("Component") + + add_offense(node.node_parts[0], message: "End ViewComponent classnames with 'Component'") + end + + private + + def view_component_class?(inheritance_klass) + inheritance_klass&.end_with?("::ApplicationComponent", "ViewComponent::Base") + end + end + end + end +end diff --git a/packages/rubocop-powerhome/lib/rubocop/cop/naming_cops.rb b/packages/rubocop-powerhome/lib/rubocop/cop/naming_cops.rb new file mode 100644 index 00000000..142df906 --- /dev/null +++ b/packages/rubocop-powerhome/lib/rubocop/cop/naming_cops.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Naming + require_relative "naming/view_component" + end + end +end diff --git a/packages/rubocop-powerhome/lib/rubocop/cop/style/no_helpers.rb b/packages/rubocop-powerhome/lib/rubocop/cop/style/no_helpers.rb new file mode 100644 index 00000000..31cac09a --- /dev/null +++ b/packages/rubocop-powerhome/lib/rubocop/cop/style/no_helpers.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Style + # This cop does not allow helpers to be placed in an application. View objects, + # specifically ViewComponent, create better Object Oriented design. + # Global helper methods tightly couple templates. + # + class NoHelpers < RuboCop::Cop::Cop + MSG = "Helpers create global view methods. Instead, use view objects to " \ + "encapsulate your display logic." + + def investigate(processed_source) + return if processed_source.blank? + return unless helper_path? + + add_offense(processed_source.ast, message: format(MSG)) + end + + private + + def helper_path? + processed_source.file_path.include?("app/helpers/") + end + end + end + end +end diff --git a/packages/rubocop-powerhome/lib/rubocop/cop/style_cops.rb b/packages/rubocop-powerhome/lib/rubocop/cop/style_cops.rb new file mode 100644 index 00000000..ddc776d4 --- /dev/null +++ b/packages/rubocop-powerhome/lib/rubocop/cop/style_cops.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Style + require_relative "style/no_helpers" + end + end +end diff --git a/packages/rubocop-powerhome/lib/rubocop/powerhome.rb b/packages/rubocop-powerhome/lib/rubocop/powerhome.rb new file mode 100644 index 00000000..f563d871 --- /dev/null +++ b/packages/rubocop-powerhome/lib/rubocop/powerhome.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module RuboCop + module Powerhome + class Error < StandardError; end + # Your code goes here... + PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze + CONFIG_DEFAULT = PROJECT_ROOT.join("config", "default.yml").freeze + CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze + + private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT) + + require_relative "powerhome/version" + require_relative "powerhome/inject" + end +end diff --git a/packages/rubocop-powerhome/lib/rubocop/powerhome/inject.rb b/packages/rubocop-powerhome/lib/rubocop/powerhome/inject.rb new file mode 100644 index 00000000..fab53ad1 --- /dev/null +++ b/packages/rubocop-powerhome/lib/rubocop/powerhome/inject.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# The original code is from https://github.com/rubocop/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb +# See https://github.com/rubocop/rubocop-rspec/blob/master/MIT-LICENSE.md +module RuboCop + module Powerhome + # Because RuboCop doesn't yet support plugins, we have to monkey patch in a + # bit of our configuration. + module Inject + def self.defaults! + path = CONFIG_DEFAULT.to_s + hash = ConfigLoader.send(:load_yaml_configuration, path) + config = Config.new(hash, path).tap(&:make_excludes_absolute) + puts "configuration from #{path}" if ConfigLoader.debug? + config = ConfigLoader.merge_with_default(config, path) + ConfigLoader.instance_variable_set(:@default_configuration, config) + end + end + end +end diff --git a/packages/rubocop-powerhome/lib/rubocop/powerhome/version.rb b/packages/rubocop-powerhome/lib/rubocop/powerhome/version.rb new file mode 100644 index 00000000..8ab60622 --- /dev/null +++ b/packages/rubocop-powerhome/lib/rubocop/powerhome/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module RuboCop + module Powerhome + VERSION = "0.5.0" + end +end diff --git a/packages/rubocop-powerhome/mkdocs.yml b/packages/rubocop-powerhome/mkdocs.yml new file mode 100644 index 00000000..1ea20f8f --- /dev/null +++ b/packages/rubocop-powerhome/mkdocs.yml @@ -0,0 +1,9 @@ +site_name: Rubocop Powerhome +site_description: Gem focused on providing standard Rubocop configuration for Power Home Remodeling ruby apps +repo_url: https://github.com/powerhome/power_linting +edit_uri: edit/main/rubocop_powerhome/docs/ +nav: + - 'Home': 'README.md' + +plugins: + - techdocs-core diff --git a/packages/rubocop-powerhome/rubocop-powerhome.gemspec b/packages/rubocop-powerhome/rubocop-powerhome.gemspec new file mode 100644 index 00000000..a1e98260 --- /dev/null +++ b/packages/rubocop-powerhome/rubocop-powerhome.gemspec @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require_relative "lib/rubocop/powerhome/version" + +Gem::Specification.new do |spec| + spec.name = "rubocop-powerhome" + spec.version = RuboCop::Powerhome::VERSION + spec.authors = ["Carlos Palhares", "Garett Arrowood"] + spec.email = ["chjunior@gmail.com", "garettarrowood@gmail.com"] + + spec.summary = "Powerhome Rubocop standard rules" + spec.description = "Powerhome Rubocop standard rules" + spec.homepage = "https://github.com/powerhome/power_linting" + spec.license = "MIT" + spec.required_ruby_version = ">= 2.7.0" + + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = spec.homepage + spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md" + + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + spec.files = Dir.chdir(File.expand_path(__dir__)) do + `git ls-files -z`.split("\x0").reject do |f| + (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + # Uncomment to register a new dependency of your gem + # spec.add_dependency "example-gem", "~> 1.0" + + # For more information and examples about making a new gem, check out our + # guide at: https://bundler.io/guides/creating_gem.html + + spec.add_runtime_dependency "rubocop" + spec.add_runtime_dependency "rubocop-performance" + spec.add_runtime_dependency "rubocop-rails" + spec.add_runtime_dependency "rubocop-rake" + spec.add_runtime_dependency "rubocop-rspec" + spec.metadata["rubygems_mfa_required"] = "true" + + spec.add_development_dependency "license_finder", "~> 7.0" + spec.add_development_dependency "pry-byebug", "3.9.0" + spec.add_development_dependency "rails", ">= 5.2.8.1" + spec.add_development_dependency "rake", "~> 13.0" + spec.add_development_dependency "rspec", "~> 3.0" + spec.add_development_dependency "rubocop", "~> 1.37.0" +end diff --git a/packages/rubocop-powerhome/sig/rubocop/powerhome.rbs b/packages/rubocop-powerhome/sig/rubocop/powerhome.rbs new file mode 100644 index 00000000..f2deed94 --- /dev/null +++ b/packages/rubocop-powerhome/sig/rubocop/powerhome.rbs @@ -0,0 +1,6 @@ +module Rubocop + module Powerhome + VERSION: String + # See the writing guide of rbs: https://github.com/ruby/rbs#guides + end +end diff --git a/packages/rubocop-powerhome/spec/rubocop/cop/naming/view_component_spec.rb b/packages/rubocop-powerhome/spec/rubocop/cop/naming/view_component_spec.rb new file mode 100644 index 00000000..93099de4 --- /dev/null +++ b/packages/rubocop-powerhome/spec/rubocop/cop/naming/view_component_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Naming::ViewComponent do + subject(:cop) { described_class.new } + + it "accepts view_component classes ending with 'Component'" do + expect_no_offenses(<<~RUBY) + class FooComponent < MyComponent::ApplicationComponent + end + RUBY + end + + it "does not register offense for class that does not inherit from ApplicationComponent or ViewComponent::Base" do + expect_no_offenses(<<~RUBY) + class Foo < ApplicationRecord + end + RUBY + end + + it "does not register offense for class that does not inherit from anything" do + expect_no_offenses(<<~RUBY) + class Foo + end + RUBY + end + + it "registers an offense when class does not end with component" do + expect_offense(<<-RUBY) + class Foo < MyComponent::ApplicationComponent + ^^^ End ViewComponent classnames with 'Component' + end + RUBY + end + + it "registers an offense when class does not end with component" do + expect_offense(<<-RUBY) + class Foo < ::ViewComponent::Base + ^^^ End ViewComponent classnames with 'Component' + end + RUBY + end +end diff --git a/packages/rubocop-powerhome/spec/rubocop/cop/style/no_helpers_spec.rb b/packages/rubocop-powerhome/spec/rubocop/cop/style/no_helpers_spec.rb new file mode 100644 index 00000000..3c532206 --- /dev/null +++ b/packages/rubocop-powerhome/spec/rubocop/cop/style/no_helpers_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe RuboCop::Cop::Style::NoHelpers do + subject(:cop) { described_class.new } + + context "does not register an offense" do + let(:source) { "contents_of_file_do_not_matter_when_no_offense" } + + it "when linting a file not in app/helpers/" do + random_file = "root/bar/random.rb" + + expect_no_offenses(source, random_file) + end + end + + context "registers an offense" do + it "when file exists inside app/helpers/" do + source = <<~RUBY + class FooHelper + ^^^^^^^^^^^^^^^ Helpers create global view methods. Instead, use view objects to encapsulate your display logic. + end + RUBY + + file_path = "app/helpers/foo_helper.rb" + + expect_offense(source, file_path) + end + end +end diff --git a/packages/rubocop-powerhome/spec/rubocop/powerhome_spec.rb b/packages/rubocop-powerhome/spec/rubocop/powerhome_spec.rb new file mode 100644 index 00000000..328ba181 --- /dev/null +++ b/packages/rubocop-powerhome/spec/rubocop/powerhome_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Powerhome do + it "has a version number" do + expect(RuboCop::Powerhome::VERSION).not_to be nil + end +end diff --git a/packages/rubocop-powerhome/spec/spec_helper.rb b/packages/rubocop-powerhome/spec/spec_helper.rb new file mode 100644 index 00000000..21a70bec --- /dev/null +++ b/packages/rubocop-powerhome/spec/spec_helper.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require "rubocop-powerhome" +require "pry-byebug" + +require "rubocop/rspec/support" + +RSpec.configure do |config| + config.include RuboCop::RSpec::ExpectOffense + + config.disable_monkey_patching! + config.raise_errors_for_deprecations! + config.raise_on_warning = true + config.fail_if_no_examples = true + + config.order = :random + Kernel.srand config.seed +end diff --git a/portal.yml b/portal.yml index efe3cfbe..fb4ba2a6 100644 --- a/portal.yml +++ b/portal.yml @@ -79,3 +79,48 @@ spec: lifecycle: production subcomponentOf: power-tools system: power-application-framework +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: eslint-config-powerhome + title: ESLint Config Powerhome + description: Provides eslint-config for Power Home Remodeling apps + annotations: + backstage.io/techdocs-ref: dir:packages/eslint-config +spec: + type: library + owner: heroes-for-hire + lifecycle: production + subcomponentOf: power-linting + system: power-application-framework +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: rubocop-cobra + title: Rubocop Cobra + description: Gem focused on providing Cops to support a healthy cobra app development + annotations: + backstage.io/techdocs-ref: dir:packages/rubocop-cobra +spec: + type: library + owner: heroes-for-hire + lifecycle: production + subcomponentOf: power-linting + system: power-application-framework +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: rubocop-powerhome + title: Rubocop Powerhome + description: Gem focused on providing standard Rubocop configuration for Power Home Remodeling ruby apps + annotations: + backstage.io/techdocs-ref: dir:packages/rubocop-powerhome +spec: + type: library + owner: heroes-for-hire + lifecycle: production + subcomponentOf: power-linting + system: power-application-framework