mirror of
https://github.com/gitlabhq/gitlabhq.git
synced 2025-07-20 16:42:55 +00:00
728 lines
21 KiB
JavaScript
728 lines
21 KiB
JavaScript
/* eslint-disable import/no-default-export */
|
|
import path from 'node:path';
|
|
import { existsSync } from 'node:fs';
|
|
import localRules from 'eslint-plugin-local-rules';
|
|
import js from '@eslint/js';
|
|
import { FlatCompat } from '@eslint/eslintrc';
|
|
// eslint-disable-next-line import/no-unresolved
|
|
import graphqlPlugin from '@graphql-eslint/eslint-plugin';
|
|
import * as todoLists from './.eslint_todo/index.mjs';
|
|
|
|
const { dirname } = import.meta;
|
|
const compat = new FlatCompat({
|
|
baseDirectory: dirname,
|
|
recommendedConfig: js.configs.recommended,
|
|
allConfig: js.configs.all,
|
|
});
|
|
|
|
const extendConfigs = [
|
|
'plugin:@gitlab/default',
|
|
'plugin:@gitlab/i18n',
|
|
'plugin:no-jquery/slim',
|
|
'plugin:no-jquery/deprecated-3.4',
|
|
'plugin:no-unsanitized/recommended-legacy',
|
|
'./tooling/eslint-config/conditionally_ignore.js',
|
|
'plugin:@gitlab/jest',
|
|
];
|
|
|
|
// Allowing JiHu to add rules on their side since the update from
|
|
// eslintrc.yml to eslint.config.mjs is not allowing subdirectory
|
|
// rewrite.
|
|
let jhConfigs = [];
|
|
if (existsSync(path.resolve(dirname, 'jh'))) {
|
|
const pathToJhConfig = path.resolve(dirname, 'jh/eslint.config.js');
|
|
// eslint-disable-next-line import/no-dynamic-require, no-unsanitized/method
|
|
jhConfigs = (await import(pathToJhConfig)).default;
|
|
}
|
|
|
|
const jestConfig = {
|
|
files: ['{,ee/}spec/frontend/**/*.js'],
|
|
|
|
settings: {
|
|
// We have to teach eslint-plugin-import what node modules we use
|
|
// otherwise there is an error when it tries to resolve them
|
|
'import/core-modules': ['events', 'fs', 'path'],
|
|
'import/resolver': {
|
|
jest: {
|
|
jestConfigFile: 'jest.config.js',
|
|
},
|
|
},
|
|
},
|
|
|
|
rules: {
|
|
'@gitlab/vtu-no-explicit-wrapper-destroy': 'error',
|
|
'jest/expect-expect': [
|
|
'off',
|
|
{
|
|
assertFunctionNames: ['expect*', 'assert*', 'testAction'],
|
|
},
|
|
],
|
|
'@gitlab/no-global-event-off': 'off',
|
|
'import/no-unresolved': [
|
|
'error',
|
|
// The test fixtures and graphql schema are dynamically generated in CI
|
|
// during the `frontend-fixtures` and `graphql-schema-dump` jobs.
|
|
// They may not be present during linting.
|
|
{
|
|
ignore: ['^test_fixtures/', 'tmp/tests/graphql/gitlab_schema.graphql'],
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
/** An object to make it easier to reuse restricted imports */
|
|
const restrictedImports = {
|
|
axios: {
|
|
name: 'axios',
|
|
message: 'Import axios from ~/lib/utils/axios_utils instead.',
|
|
},
|
|
mousetrap: {
|
|
name: 'mousetrap',
|
|
message: 'Import { Mousetrap } from ~/lib/mousetrap instead.',
|
|
},
|
|
sentry: {
|
|
name: '@sentry/browser',
|
|
message: 'Use "import * as Sentry from \'~/sentry/sentry_browser_wrapper\';" instead',
|
|
},
|
|
vuex: {
|
|
name: 'vuex',
|
|
message:
|
|
'See our documentation on "Migrating from VueX" for tips on how to avoid adding new VueX stores.',
|
|
},
|
|
};
|
|
|
|
export default [
|
|
{
|
|
ignores: [
|
|
'app/assets/javascripts/locale/**/app.js',
|
|
'builds/',
|
|
'coverage/',
|
|
'coverage-frontend/',
|
|
'node_modules/',
|
|
'public/',
|
|
'tmp/',
|
|
'vendor/',
|
|
'sitespeed-result/',
|
|
'fixtures/**/*.graphql',
|
|
'storybook/public',
|
|
'spec/fixtures/**/*.graphql',
|
|
],
|
|
},
|
|
...compat.extends(...extendConfigs),
|
|
...compat.plugins('no-jquery'),
|
|
{
|
|
rules: {
|
|
'no-unused-vars': [
|
|
'error',
|
|
{
|
|
caughtErrors: 'none',
|
|
ignoreRestSiblings: true,
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: ['**/*.{js,vue}'],
|
|
|
|
plugins: {
|
|
'local-rules': localRules,
|
|
},
|
|
|
|
languageOptions: {
|
|
globals: {
|
|
__webpack_public_path__: true,
|
|
gl: false,
|
|
gon: false,
|
|
localStorage: false,
|
|
IS_EE: false,
|
|
},
|
|
},
|
|
|
|
settings: {
|
|
'import/resolver': {
|
|
webpack: {
|
|
config: './config/webpack.config.js',
|
|
},
|
|
},
|
|
},
|
|
|
|
rules: {
|
|
'import/no-commonjs': 'error',
|
|
'import/no-default-export': 'off',
|
|
// Use dependency-cruiser to get an accurate analysis on circular dependencies
|
|
// and for better performance
|
|
'import/no-cycle': 'off',
|
|
|
|
'no-underscore-dangle': [
|
|
'error',
|
|
{
|
|
allow: ['__', '_links'],
|
|
},
|
|
],
|
|
|
|
'import/no-unresolved': [
|
|
'error',
|
|
{
|
|
ignore: ['^(ee|jh)_component/', '^jh_else_ee/'],
|
|
},
|
|
],
|
|
|
|
'lines-between-class-members': 'off',
|
|
'no-jquery/no-animate-toggle': 'off',
|
|
'no-jquery/no-event-shorthand': 'off',
|
|
'no-jquery/no-serialize': 'error',
|
|
'promise/always-return': 'off',
|
|
'promise/no-callback-in-promise': 'off',
|
|
'@gitlab/no-global-event-off': 'error',
|
|
|
|
'@gitlab/vue-no-new-non-primitive-in-template': [
|
|
'error',
|
|
{
|
|
allowNames: ['class(es)?$', '^style$', '^to$', '^$', '^variables$', 'attrs?$'],
|
|
},
|
|
],
|
|
|
|
'@gitlab/vue-no-undef-apollo-properties': 'error',
|
|
'@gitlab/tailwind-no-interpolation': 'error',
|
|
'@gitlab/vue-tailwind-no-interpolation': 'error',
|
|
'@gitlab/tailwind-no-max-width-media-queries': 'error',
|
|
'@gitlab/vue-tailwind-no-max-width-media-queries': 'error',
|
|
|
|
'no-param-reassign': [
|
|
'error',
|
|
{
|
|
props: true,
|
|
ignorePropertyModificationsFor: ['acc', 'accumulator', 'el', 'element', 'state'],
|
|
ignorePropertyModificationsForRegex: ['^draft'],
|
|
},
|
|
],
|
|
|
|
'import/order': [
|
|
'error',
|
|
{
|
|
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
|
|
|
|
pathGroups: [
|
|
{
|
|
pattern: '~/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: 'emojis/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: '{ee_,jh_,}empty_states/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: '{ee_,jh_,}icons/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: '{ee_,jh_,}images/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: 'vendor/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: 'shared_queries/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: '{ee_,}spec/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: '{ee_,jh_,}jest/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: '{ee_,jh_,any_}else_ce/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: 'ee/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: '{ee_,jh_,}component/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: 'jh_else_ee/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: 'jh/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: '{test_,}helpers/**',
|
|
group: 'internal',
|
|
},
|
|
{
|
|
pattern: 'test_fixtures/**',
|
|
group: 'internal',
|
|
},
|
|
],
|
|
|
|
alphabetize: {
|
|
order: 'ignore',
|
|
},
|
|
},
|
|
],
|
|
|
|
'no-restricted-syntax': [
|
|
'error',
|
|
{
|
|
selector: "ImportSpecifier[imported.name='GlSkeletonLoading']",
|
|
message: 'Migrate to GlSkeletonLoader, or import GlDeprecatedSkeletonLoading.',
|
|
},
|
|
{
|
|
selector: "ImportSpecifier[imported.name='GlSafeHtmlDirective']",
|
|
message: 'Use directive at ~/vue_shared/directives/safe_html.js instead.',
|
|
},
|
|
{
|
|
selector: 'Literal[value=/docs.gitlab.+\\u002Fee/]',
|
|
message:
|
|
'No hard coded url, use `DOCS_URL_IN_EE_DIR` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'TemplateElement[value.cooked=/docs.gitlab.+\\u002Fee/]',
|
|
message:
|
|
'No hard coded url, use `DOCS_URL_IN_EE_DIR` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'Literal[value=/(?=.*docs.gitlab.*)(?!.*\\u002Fee\\b.*)/]',
|
|
message: 'No hard coded url, use `DOCS_URL` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'TemplateElement[value.cooked=/(?=.*docs.gitlab.*)(?!.*\\u002Fee\\b.*)/]',
|
|
message: 'No hard coded url, use `DOCS_URL` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'Literal[value=/(?=.*about.gitlab.*)(?!.*\\u002Fblog\\b.*)/]',
|
|
message: 'No hard coded url, use `PROMO_URL` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'TemplateElement[value.cooked=/(?=.*about.gitlab.*)(?!.*\\u002Fblog\\b.*)/]',
|
|
message: 'No hard coded url, use `PROMO_URL` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector:
|
|
'TemplateLiteral[expressions.0.name=DOCS_URL] > TemplateElement[value.cooked=/\\u002Fjh|\\u002Fee/]',
|
|
message:
|
|
'`/ee` or `/jh` path found in docs url, use `DOCS_URL_IN_EE_DIR` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector:
|
|
"MemberExpression[object.type='ThisExpression'][property.name=/(\\$delete|\\$set)/]",
|
|
message:
|
|
"Vue 2's set/delete methods are not available in Vue 3. Create/assign new objects with the desired properties instead.",
|
|
},
|
|
],
|
|
|
|
'no-restricted-properties': [
|
|
'error',
|
|
{
|
|
object: 'window',
|
|
property: 'open',
|
|
message:
|
|
'Use `visitUrl` in `jh_else_ce/lib/utils/url_utility` to avoid cross-site leaks.',
|
|
},
|
|
{
|
|
object: 'vm',
|
|
property: '$delete',
|
|
message:
|
|
"Vue 2's set/delete methods are not available in Vue 3. Create/assign new objects with the desired properties instead.",
|
|
},
|
|
{
|
|
object: 'Vue',
|
|
property: 'delete',
|
|
message:
|
|
"Vue 2's set/delete methods are not available in Vue 3. Create/assign new objects with the desired properties instead.",
|
|
},
|
|
{
|
|
object: 'vm',
|
|
property: '$set',
|
|
message:
|
|
"Vue 2's set/delete methods are not available in Vue 3. Create/assign new objects with the desired properties instead.",
|
|
},
|
|
{
|
|
object: 'Vue',
|
|
property: 'set',
|
|
message:
|
|
"Vue 2's set/delete methods are not available in Vue 3. Create/assign new objects with the desired properties instead.",
|
|
},
|
|
],
|
|
|
|
'no-restricted-imports': [
|
|
'error',
|
|
{
|
|
paths: [
|
|
restrictedImports.axios,
|
|
restrictedImports.mousetrap,
|
|
restrictedImports.sentry,
|
|
restrictedImports.vuex,
|
|
],
|
|
|
|
patterns: [
|
|
{
|
|
group: ['react', 'react-dom/*'],
|
|
message:
|
|
'We do not allow usage of React in our codebase except for the graphql_explorer',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
|
|
'unicorn/prefer-dom-node-dataset': ['error'],
|
|
|
|
'no-unsanitized/method': [
|
|
'error',
|
|
{
|
|
escape: {
|
|
methods: ['sanitize'],
|
|
},
|
|
},
|
|
],
|
|
|
|
'no-unsanitized/property': [
|
|
'error',
|
|
{
|
|
escape: {
|
|
methods: ['sanitize'],
|
|
},
|
|
},
|
|
],
|
|
|
|
'unicorn/no-array-callback-reference': 'off',
|
|
|
|
'vue/no-undef-components': [
|
|
'error',
|
|
{
|
|
ignorePatterns: ['^router-link$', '^router-view$', '^gl-emoji$'],
|
|
},
|
|
],
|
|
|
|
'local-rules/require-valid-help-page-path': 'error',
|
|
'local-rules/vue-require-valid-help-page-link-component': 'error',
|
|
},
|
|
},
|
|
{
|
|
files: ['**/*.vue'],
|
|
rules: {
|
|
'vue/no-unused-properties': [
|
|
'error',
|
|
{
|
|
groups: ['props', 'data', 'computed', 'methods'],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: ['{,ee/,jh/}spec/frontend*/**/*'],
|
|
|
|
rules: {
|
|
'@gitlab/require-i18n-strings': 'off',
|
|
'@gitlab/no-runtime-template-compiler': 'off',
|
|
'@gitlab/tailwind-no-interpolation': 'off',
|
|
'@gitlab/vue-tailwind-no-interpolation': 'off',
|
|
'@gitlab/no-max-width-media-queries': 'off',
|
|
'@gitlab/vue-tailwind-no-max-width-media-queries': 'off',
|
|
'require-await': 'error',
|
|
'import/no-dynamic-require': 'off',
|
|
'no-import-assign': 'off',
|
|
|
|
'no-restricted-syntax': [
|
|
'error',
|
|
{
|
|
selector:
|
|
'CallExpression[callee.object.name=/(wrapper|vm)/][callee.property.name="setData"]',
|
|
message: 'Avoid using "setData" on VTU wrapper',
|
|
},
|
|
{
|
|
selector:
|
|
"MemberExpression[object.type!='ThisExpression'][property.type='Identifier'][property.name='$nextTick']",
|
|
message:
|
|
'Using $nextTick from a component instance is discouraged. Import nextTick directly from the Vue package.',
|
|
},
|
|
{
|
|
selector: "Identifier[name='setImmediate']",
|
|
message:
|
|
'Prefer explicit waitForPromises (or equivalent), or jest.runAllTimers (or equivalent) to vague setImmediate calls.',
|
|
},
|
|
{
|
|
selector: "ImportSpecifier[imported.name='GlSkeletonLoading']",
|
|
message: 'Migrate to GlSkeletonLoader, or import GlDeprecatedSkeletonLoading.',
|
|
},
|
|
{
|
|
selector:
|
|
"CallExpression[arguments.length=1][arguments.0.type='Literal'] CallExpression[callee.property.name='toBe'] CallExpression[callee.property.name='attributes'][arguments.length=1][arguments.0.value='disabled']",
|
|
message:
|
|
'Avoid asserting disabled attribute exact value, because Vue.js 2 and Vue.js 3 renders it differently. Use toBeDefined / toBeUndefined instead',
|
|
},
|
|
{
|
|
selector:
|
|
"MemberExpression[object.object.name='Vue'][object.property.name='config'][property.name='errorHandler']",
|
|
message:
|
|
'Use setErrorHandler/resetVueErrorHandler from helpers/set_vue_error_handler.js instead.',
|
|
},
|
|
{
|
|
selector: 'Literal[value=/docs.gitlab.+\\u002Fee/]',
|
|
message:
|
|
'No hard coded url, use `DOCS_URL_IN_EE_DIR` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'TemplateElement[value.cooked=/docs.gitlab.+\\u002Fee/]',
|
|
message:
|
|
'No hard coded url, use `DOCS_URL_IN_EE_DIR` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'Literal[value=/(?=.*docs.gitlab.*)(?!.*\\u002Fee\\b.*)/]',
|
|
message: 'No hard coded url, use `DOCS_URL` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'TemplateElement[value.cooked=/(?=.*docs.gitlab.*)(?!.*\\u002Fee\\b.*)/]',
|
|
message: 'No hard coded url, use `DOCS_URL` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'Literal[value=/(?=.*about.gitlab.*)(?!.*\\u002Fblog\\b.*)/]',
|
|
message: 'No hard coded url, use `PROMO_URL` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'TemplateElement[value.cooked=/(?=.*about.gitlab.*)(?!.*\\u002Fblog\\b.*)/]',
|
|
message: 'No hard coded url, use `PROMO_URL` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector:
|
|
'TemplateLiteral[expressions.0.name=DOCS_URL] > TemplateElement[value.cooked=/\\u002Fjh|\\u002Fee/]',
|
|
message:
|
|
'`/ee` or `/jh` path found in docs url, use `DOCS_URL_IN_EE_DIR` in `jh_else_ce/lib/utils/url_utility`',
|
|
},
|
|
{
|
|
selector: 'CallExpression[callee.property.name=/(\\$delete|\\$set)/]',
|
|
message:
|
|
"Vue 2's set/delete methods are not available in Vue 3. Create/assign new objects with the desired properties instead.",
|
|
},
|
|
],
|
|
|
|
'no-restricted-properties': [
|
|
'error',
|
|
{
|
|
object: 'Vue',
|
|
property: 'delete',
|
|
message:
|
|
"Vue 2's set/delete methods are not available in Vue 3. Create/assign new objects with the desired properties instead.",
|
|
},
|
|
{
|
|
object: 'Vue',
|
|
property: 'set',
|
|
message:
|
|
"Vue 2's set/delete methods are not available in Vue 3. Create/assign new objects with the desired properties instead.",
|
|
},
|
|
],
|
|
|
|
'no-unsanitized/method': 'off',
|
|
'no-unsanitized/property': 'off',
|
|
'local-rules/require-valid-help-page-path': 'off',
|
|
'local-rules/vue-require-valid-help-page-link-component': 'off',
|
|
|
|
'no-restricted-imports': [
|
|
'error',
|
|
{
|
|
paths: [
|
|
restrictedImports.axios,
|
|
restrictedImports.mousetrap,
|
|
restrictedImports.sentry,
|
|
restrictedImports.vuex,
|
|
{
|
|
name: '~/locale',
|
|
importNames: ['__', 's__'],
|
|
message:
|
|
'Do not externalize strings in specs: https://docs.gitlab.com/ee/development/i18n/externalization.html#test-files-jest',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: [
|
|
'config/**/*',
|
|
'scripts/**/*',
|
|
'**/*.config.js',
|
|
'**/*.config.*.js',
|
|
'**/jest_resolver.js',
|
|
'eslint.config.mjs',
|
|
],
|
|
|
|
rules: {
|
|
'@gitlab/require-i18n-strings': 'off',
|
|
'import/extensions': 'off',
|
|
'import/no-extraneous-dependencies': 'off',
|
|
'import/no-commonjs': 'off',
|
|
'import/no-nodejs-modules': 'off',
|
|
'filenames/match-regex': 'off',
|
|
'no-console': 'off',
|
|
},
|
|
},
|
|
{
|
|
files: ['**/*.stories.js'],
|
|
|
|
rules: {
|
|
'filenames/match-regex': 'off',
|
|
'@gitlab/require-i18n-strings': 'off',
|
|
'import/no-unresolved': [
|
|
'error',
|
|
// The test fixtures are dynamically generated in CI during
|
|
// the `frontend-fixtures` job. They may not be present during linting.
|
|
{
|
|
ignore: ['^test_fixtures/'],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
files: ['**/*.graphql'],
|
|
|
|
languageOptions: {
|
|
|
|
parserOptions: {
|
|
parser: graphqlPlugin.parser,
|
|
graphQLConfig: {
|
|
documents: '{,ee/,jh/}app/**/*.graphql',
|
|
schema: './tmp/tests/graphql/gitlab_schema_apollo.graphql',
|
|
},
|
|
},
|
|
},
|
|
|
|
plugins: {
|
|
'@graphql-eslint': graphqlPlugin,
|
|
},
|
|
|
|
rules: {
|
|
'filenames/match-regex': 'off',
|
|
'spaced-comment': 'off',
|
|
'@graphql-eslint/no-anonymous-operations': 'error',
|
|
'@graphql-eslint/unique-operation-name': 'error',
|
|
'@graphql-eslint/require-selections': 'error',
|
|
'@graphql-eslint/no-unused-variables': 'error',
|
|
'@graphql-eslint/no-unused-fragments': 'error',
|
|
'@graphql-eslint/no-duplicate-fields': 'error',
|
|
},
|
|
},
|
|
{
|
|
files: [
|
|
'app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql',
|
|
'app/assets/javascripts/projects/settings/repository/branch_rules/graphql/mutations/create_branch_rule.mutation.graphql',
|
|
'app/assets/javascripts/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql',
|
|
'ee/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql',
|
|
'ee/app/assets/javascripts/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql',
|
|
],
|
|
|
|
rules: {
|
|
'@graphql-eslint/require-selections': 'off',
|
|
},
|
|
},
|
|
{
|
|
files: ['{,spec/}tooling/**/*'],
|
|
|
|
rules: {
|
|
'no-undef': 'off',
|
|
'import/no-commonjs': 'off',
|
|
'import/no-extraneous-dependencies': 'off',
|
|
'no-restricted-syntax': 'off',
|
|
'@gitlab/require-i18n-strings': 'off',
|
|
},
|
|
},
|
|
|
|
// JIRA subscriptions config
|
|
{
|
|
files: ['app/assets/javascripts/jira_connect/subscriptions/**/*.{js,vue}'],
|
|
|
|
languageOptions: {
|
|
globals: {
|
|
AP: 'readonly',
|
|
},
|
|
},
|
|
|
|
rules: {
|
|
'@gitlab/require-i18n-strings': 'off',
|
|
'@gitlab/vue-require-i18n-strings': 'off',
|
|
},
|
|
},
|
|
|
|
// Storybook config
|
|
{
|
|
files: ['storybook/**/*.{js,vue}'],
|
|
|
|
rules: {
|
|
'@gitlab/require-i18n-strings': 'off',
|
|
'import/no-extraneous-dependencies': 'off',
|
|
'import/no-commonjs': 'off',
|
|
'import/no-nodejs-modules': 'off',
|
|
'filenames/match-regex': 'off',
|
|
'no-console': 'off',
|
|
'import/no-unresolved': 'off',
|
|
},
|
|
},
|
|
|
|
// Jest config
|
|
jestConfig,
|
|
|
|
// Integration tests config
|
|
{
|
|
files: ['{,ee/}spec/frontend_integration/**/*.js'],
|
|
|
|
settings: {
|
|
...jestConfig.settings,
|
|
'import/resolver': {
|
|
jest: {
|
|
jestConfigFile: 'jest.config.integration.js',
|
|
},
|
|
},
|
|
},
|
|
|
|
rules: {
|
|
...jestConfig.rules,
|
|
'no-restricted-imports': ['error', 'fs'],
|
|
},
|
|
|
|
languageOptions: {
|
|
globals: {
|
|
mockServer: false,
|
|
},
|
|
},
|
|
},
|
|
|
|
/*
|
|
contracts specs are a little different, as they are not "normal" jest specs.
|
|
|
|
They are actually executing `jest` and e.g. do proper non-mocked calls with axios in order
|
|
to check API contracts.
|
|
|
|
They also do not directly execute library code, so some of our usual linting rules for app code
|
|
like no-restricted-imports or i18n rules make no sense here and we can disable them.
|
|
|
|
For reference: https://docs.gitlab.com/development/testing_guide/contract/
|
|
*/
|
|
{
|
|
files: ['{,ee/}spec/contracts/consumer/**/*.js'],
|
|
|
|
settings: {
|
|
'import/core-modules': ['@pact-foundation/pact', 'jest-pact'],
|
|
},
|
|
|
|
rules: {
|
|
'@gitlab/require-i18n-strings': 'off',
|
|
'no-restricted-imports': 'off',
|
|
},
|
|
},
|
|
...jhConfigs,
|
|
...Object.values(todoLists),
|
|
];
|