{ "root": true, "env": { "es2022": true, "commonjs": true }, "extends": [ "standard", "plugin:import/recommended", "plugin:promise/recommended", "plugin:n/recommended" ], "parserOptions": { "ecmaVersion": 2022 }, "ignorePatterns": ["frontend/dist/", "var/", "*.svg", "*.xml"], "plugins": ["promise", "no-only-tests"], "settings": { "import/core-modules": [ "lottie-web-vue", "@heroicons/vue" ], "node": { "allowModules": [ "flowforge-test-utils", // exists at test/node_modules/flowforge-test-utils "promptly", "lottie-web-vue", "@heroicons/vue" ] } }, "rules": { // Inbuilt "indent": ["error", 4], "object-shorthand": ["error"], "sort-imports": [ "error", { "ignoreDeclarationSort": true } ], "no-console": ["error", { "allow": ["debug", "info", "warn", "error"] }], // plugin:import "import/order": [ "error", { "alphabetize": { "order": "asc" }, "newlines-between": "always-and-inside-groups" } ], "import/no-unresolved": "error", // plugin:n "n/file-extension-in-import": "error", "n/no-missing-import": "error", "n/no-missing-require": "error", // plugin:no-only-tests "no-only-tests/no-only-tests": "error", // plugin:promise "promise/catch-or-return": ["error", { "allowFinally": true }] }, "overrides": [ // Frontend runs in the browser and builds with webpack { "files": "frontend/**", "extends": ["plugin:vue/vue3-recommended"], "env": { "browser": true, "commonjs": false }, "parserOptions": { "ecmaVersion": 2022, "sourceType": "module" }, "rules": { // plugin:vue "vue/html-indent": ["warn", 4], // plugin:vue - style rules "vue/max-attributes-per-line": "off", "vue/attribute-hyphenation": "off", "vue/singleline-html-element-content-newline": "off", // plugin:promise "promise/always-return": "off" // common Vue.js pattern } }, // UI components use kebab-case { "files": "frontend/src/ui-components/**", "rules": { "vue/component-definition-name-casing": ["error", "kebab-case"], "vue/first-attribute-linebreak": "off", "vue/html-self-closing": "off" } }, // System, unit, and E2E tests run using Mocha { "files": ["test/**"], "env": { "mocha": true } }, // Cypress is used for E2E { "files": "test/e2e/**", "env": { "cypress/globals": true }, "extends": ["plugin:cypress/recommended"], "plugins": ["cypress"], "rules": { // plugin:cypress "cypress/require-data-selectors": "warn", "cypress/assertion-before-screenshot": "error", "cypress/no-force": "warn", "cypress/no-pause": "error", // plugin:n "promise/always-return": "off", "promise/catch-or-return": "off" } }, // Front ends tests are modules { "files": ["test/unit/frontend/**", "test/e2e/frontend/**"], "parserOptions": { "sourceType": "module" } }, ////////// // Auto-generated rule overrides for old files that fail on newly introduced rules ////////// { "rules": { "cypress/require-data-selectors": "off" }, "files": [ "test/e2e/frontend/cypress/tests/admin.spec.js", "test/e2e/frontend/cypress/tests/admin/instance-types.spec.js", "test/e2e/frontend/cypress/tests/admin/stacks.spec.js", "test/e2e/frontend/cypress/tests/admin/templates.spec.js", "test/e2e/frontend/cypress/tests/applications.spec.js", "test/e2e/frontend/cypress/tests/auth.spec.js", "test/e2e/frontend/cypress/tests/devices.spec.js", "test/e2e/frontend/cypress/tests/instances.spec.js", "test/e2e/frontend/cypress/tests/instances/devices.spec.js", "test/e2e/frontend/cypress/tests/instances/snapshots.spec.js", "test/e2e/frontend/cypress/tests/instances/staging.spec.js", "test/e2e/frontend/cypress/tests/invitations.spec.js", "test/e2e/frontend/cypress/tests/team/team.spec.js", "test/e2e/frontend/cypress/tests/team/audit-log.spec.js", "test/e2e/frontend/cypress/tests/team/team-membership.spec.js", "test/e2e/frontend/cypress/tests/terms-and-conditions.spec.js" ] }, { "rules": { "promise/catch-or-return": "off" }, "files": [ "frontend/src/pages/instance/Overview.vue" ] }, { "rules": { "vue/attributes-order": "off" }, "files": [ "frontend/src/components/auth/UpdateExpiredPassword.vue", "frontend/src/components/FormRow.vue", "frontend/src/components/NavItem.vue", "frontend/src/components/PageHeader.vue", "frontend/src/components/SectionTopMenu.vue", "frontend/src/components/TeamSelection.vue", "frontend/src/pages/device/Overview.vue", "frontend/src/pages/device/Settings/Danger.vue", "frontend/src/pages/device/Settings/dialogs/ConfirmDeviceDeleteDialog.vue", "frontend/src/pages/device/Settings/Environment.vue", "frontend/src/pages/device/Settings/General.vue", "frontend/src/pages/team/components/MemberSummaryList.vue", "frontend/src/pages/team/components/ProjectSummaryList.vue", "frontend/src/pages/team/Devices/dialogs/CreateProvisioningTokenDialog.vue" ] }, { "rules": { "vue/component-definition-name-casing": "off" }, "files": [ "frontend/src/components/Accordion.vue", "frontend/src/components/CodePreviewer.vue", "frontend/src/components/Loading.vue", "frontend/src/layouts/Box.vue", "frontend/src/layouts/Platform.vue", "frontend/src/main.js" ] }, { "rules": { "vue/order-in-components": "off" }, "files": [ "frontend/src/components/audit-log/AuditEntry.vue", "frontend/src/components/audit-log/AuditEntryIcon.vue", "frontend/src/components/audit-log/AuditEntryVerbose.vue", "frontend/src/components/audit-log/AuditLog.vue", "frontend/src/components/auth/UpdateExpiredPassword.vue", "frontend/src/components/DropdownMenu.vue", "frontend/src/components/FormRow.vue", "frontend/src/components/PageHeader.vue", "frontend/src/components/SectionTopMenu.vue", "frontend/src/components/tables/cells/InviteUserCell.vue", "frontend/src/components/TeamSelection.vue", "frontend/src/pages/device/components/DeviceLastSeenBadge.vue", "frontend/src/pages/device/Overview.vue", "frontend/src/pages/device/Settings/Danger.vue", "frontend/src/pages/device/Settings/dialogs/ConfirmDeviceDeleteDialog.vue", "frontend/src/pages/device/Settings/Environment.vue", "frontend/src/pages/device/Settings/General.vue", "frontend/src/pages/device/Settings/index.vue", "frontend/src/pages/team/components/LibraryEntryTypeIcon.vue", "frontend/src/pages/team/components/MemberSummaryList.vue", "frontend/src/pages/team/components/ProjectSummaryList.vue", "frontend/src/pages/team/components/TeamUserEditButton.vue", "frontend/src/pages/team/create.vue", "frontend/src/pages/team/Devices/dialogs/CreateProvisioningTokenDialog.vue", "frontend/src/pages/team/Devices/dialogs/DeviceCredentialsDialog.vue", "frontend/src/pages/team/Devices/dialogs/ProvisioningCredentialsDialog.vue", "frontend/src/pages/team/dialogs/ChangeTeamRoleDialog.vue", "frontend/src/pages/team/dialogs/ConfirmTeamDeleteDialog.vue", "frontend/src/pages/team/dialogs/ConfirmTeamUserRemoveDialog.vue" ] }, { "rules": { "vue/require-prop-types": "off" }, "files": [ "frontend/src/components/DropdownMenu.vue", "frontend/src/components/FormRow.vue", "frontend/src/components/SectionSideMenu.vue", "frontend/src/components/SideNavigation.vue", "frontend/src/components/tables/cells/InviteUserCell.vue", "frontend/src/components/tables/cells/TeamCell.vue", "frontend/src/components/tables/cells/TeamTypeCell.vue", "frontend/src/components/tables/cells/UserCell.vue", "frontend/src/components/tables/cells/UserRoleCell.vue", "frontend/src/pages/application/components/ExportProjectComponents.vue", "frontend/src/pages/application/components/ImportProjectComponents.vue", "frontend/src/pages/application/Debug.vue", "frontend/src/pages/device/components/DeviceLastSeenBadge.vue", "frontend/src/pages/device/Overview.vue", "frontend/src/pages/device/Settings/Danger.vue", "frontend/src/pages/device/Settings/Environment.vue", "frontend/src/pages/device/Settings/General.vue", "frontend/src/pages/device/Settings/index.vue", "frontend/src/pages/instance/components/ExportInstanceComponents.vue", "frontend/src/pages/instance/components/ImportInstanceComponents.vue", "frontend/src/pages/team/components/MemberSummaryList.vue", "frontend/src/pages/team/components/ProjectSummaryList.vue", "frontend/src/pages/team/components/ProjectTypeSummary.vue", "frontend/src/pages/team/components/TeamUserEditButton.vue", "frontend/src/pages/team/Devices/dialogs/CreateProvisioningTokenDialog.vue", "frontend/src/pages/team/Devices/dialogs/DeviceCredentialsDialog.vue", "frontend/src/pages/team/Devices/dialogs/ProvisioningCredentialsDialog.vue" ] } ] }