dify/lint.config.ts

1605 lines
55 KiB
TypeScript

import type { OxlintConfig } from 'vite-plus/lint'
import path from 'node:path'
const rootDir = import.meta.dirname
const difyUiPackageJson = path.resolve(rootDir, 'packages/dify-ui/package.json')
/**
* Oxlint equivalent of the ESLint configurations that were active before the migration.
* Keep rules explicit so changes in upstream presets do not silently alter the lint baseline.
*/
export const lintConfig = {
categories: {
correctness: 'off',
},
env: {
builtin: true,
es2026: true,
browser: true,
node: true,
},
ignorePatterns: [
'.agents/**',
'.claude/**',
'.devcontainer/**',
'.github/**',
'.vscode/**',
'api/**',
'cli/context/**',
'cli/coverage/**',
'cli/dist/**',
'cli/docs/**',
'dify-agent/**',
'docker/**',
'docs/**',
'scripts/**',
'sdks/php-client/**',
'sdks/python-client/**',
'**/.next/**',
'**/.vinext/**',
'**/coverage/**',
'**/dist/**',
'**/*.d.{ts,cts,mts}',
'**/storybook-static/**',
'e2e/.auth/**',
'e2e/cucumber-report/**',
'packages/contracts/**',
'web/next/**',
'web/next-env.d.ts',
'web/public/**',
'web/types/doc-paths.ts',
],
plugins: ['import', 'jsdoc', 'jsx-a11y', 'node', 'react', 'typescript', 'unicorn', 'vitest'],
// Keep JavaScript plugins ordered by rule namespace. The `-js` aliases distinguish
// plugins that supplement an active native Oxlint plugin with the same namespace.
jsPlugins: [
'@tanstack/eslint-plugin-query',
'eslint-plugin-antfu',
'eslint-plugin-command',
'eslint-plugin-erasable-syntax-only',
{
name: 'eslint-comments',
specifier: '@eslint-community/eslint-plugin-eslint-comments',
},
{
name: 'eslint-react',
specifier: '@eslint-react/eslint-plugin',
},
'eslint-plugin-hyoban',
{
name: 'jsdoc-js',
specifier: 'eslint-plugin-jsdoc',
},
'eslint-plugin-no-barrel-files',
{
name: 'node-js',
specifier: 'eslint-plugin-n',
},
'eslint-plugin-perfectionist',
'eslint-plugin-regexp',
'eslint-plugin-storybook',
],
options: {
reportUnusedDisableDirectives: 'warn',
respectEslintDisableDirectives: false,
typeAware: true,
typeCheck: true,
},
settings: {
'react-x': {
additionalStateHooks: '/^use\\w*State(?:s)?|useAtom$/u',
},
},
rules: {
'accessor-pairs': [
'error',
{
enforceForClassMembers: true,
setWithoutGet: true,
},
],
'antfu/no-top-level-await': 'error',
'array-callback-return': 'error',
'block-scoped-var': 'error',
'constructor-super': 'error',
'default-case-last': 'error',
eqeqeq: ['error', 'smart'],
'new-cap': [
'error',
{
capIsNew: false,
newIsCap: true,
properties: true,
},
],
'no-alert': 'error',
'no-array-constructor': 'error',
'no-async-promise-executor': 'error',
'no-caller': 'error',
'no-case-declarations': 'error',
'no-class-assign': 'error',
'no-compare-neg-zero': 'error',
'no-cond-assign': ['error', 'always'],
'no-console': [
'error',
{
allow: ['warn', 'error'],
},
],
'no-const-assign': 'error',
'no-control-regex': 'off',
'no-debugger': 'error',
'no-delete-var': 'error',
'no-dupe-class-members': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-empty': [
'error',
{
allowEmptyCatch: true,
},
],
'no-empty-pattern': 'error',
'no-eval': 'error',
'no-ex-assign': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'error',
'no-extra-boolean-cast': 'error',
'no-fallthrough': 'error',
'no-func-assign': 'error',
'no-global-assign': 'error',
'no-implied-eval': 'error',
'no-import-assign': 'error',
'no-irregular-whitespace': 'error',
'no-iterator': 'error',
'no-labels': [
'error',
{
allowLoop: false,
allowSwitch: false,
},
],
'no-lone-blocks': 'error',
'no-loss-of-precision': 'error',
'no-misleading-character-class': 'error',
'no-multi-str': 'error',
'no-new': 'error',
'no-new-func': 'error',
'no-new-native-nonconstructor': 'error',
'no-new-wrappers': 'error',
'no-obj-calls': 'error',
'no-proto': 'error',
'no-prototype-builtins': 'error',
'no-redeclare': [
'error',
{
builtinGlobals: false,
},
],
'no-regex-spaces': 'error',
'no-restricted-globals': [
'error',
{
message: 'Use `globalThis` instead.',
name: 'global',
},
{
message: 'Use `globalThis` instead.',
name: 'self',
},
],
'no-restricted-properties': [
'error',
{
message: 'Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.',
property: '__proto__',
},
{
message: 'Use `Object.defineProperty` instead.',
property: '__defineGetter__',
},
{
message: 'Use `Object.defineProperty` instead.',
property: '__defineSetter__',
},
{
message: 'Use `Object.getOwnPropertyDescriptor` instead.',
property: '__lookupGetter__',
},
{
message: 'Use `Object.getOwnPropertyDescriptor` instead.',
property: '__lookupSetter__',
},
],
'no-self-assign': [
'error',
{
props: true,
},
],
'no-self-compare': 'error',
'no-sequences': 'error',
'no-shadow-restricted-names': 'error',
'no-sparse-arrays': 'error',
'no-template-curly-in-string': 'error',
'no-this-before-super': 'error',
'no-throw-literal': 'error',
'no-unexpected-multiline': 'error',
'no-unmodified-loop-condition': 'error',
'no-unneeded-ternary': [
'error',
{
defaultAssignment: false,
},
],
'no-unreachable': 'error',
'no-unsafe-finally': 'error',
'no-unsafe-negation': 'error',
'no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true,
},
],
'no-unused-vars': [
'error',
{
args: 'after-used',
argsIgnorePattern: '^_',
caughtErrors: 'none',
fix: {
imports: 'safe-fix',
variables: 'off',
},
ignoreRestSiblings: true,
vars: 'all',
varsIgnorePattern: '^_',
},
],
'no-use-before-define': [
'error',
{
classes: false,
functions: false,
variables: true,
},
],
'no-useless-call': 'error',
'no-useless-catch': 'error',
'no-useless-computed-key': 'error',
'no-useless-constructor': 'error',
'no-useless-rename': 'error',
'no-useless-return': 'error',
'no-var': 'error',
'no-with': 'error',
'object-shorthand': [
'error',
'always',
{
avoidQuotes: true,
ignoreConstructors: false,
},
],
'prefer-arrow-callback': [
'error',
{
allowNamedFunctions: false,
allowUnboundThis: true,
},
],
'prefer-const': [
'error',
{
destructuring: 'all',
ignoreReadBeforeAssign: true,
},
],
'prefer-exponentiation-operator': 'error',
'prefer-promise-reject-errors': 'error',
'prefer-regex-literals': [
'error',
{
disallowRedundantWrapping: true,
},
],
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'prefer-template': 'error',
'symbol-description': 'error',
'unicode-bom': ['error', 'never'],
'use-isnan': [
'error',
{
enforceForIndexOf: true,
enforceForSwitchCase: true,
},
],
'valid-typeof': [
'error',
{
requireStringLiterals: true,
},
],
'vars-on-top': 'error',
yoda: ['error', 'never'],
'eslint-comments/no-aggregating-enable': 'error',
'eslint-comments/no-duplicate-disable': 'error',
'eslint-comments/no-unlimited-disable': 'error',
'eslint-comments/no-unused-enable': 'error',
'command/command': 'error',
'perfectionist/sort-exports': [
'error',
{
order: 'asc',
type: 'natural',
},
],
'perfectionist/sort-named-exports': [
'error',
{
order: 'asc',
type: 'natural',
},
],
'perfectionist/sort-named-imports': [
'error',
{
order: 'asc',
type: 'natural',
},
],
'antfu/import-dedupe': 'error',
'antfu/no-import-dist': 'error',
'antfu/no-import-node-modules-by-path': 'error',
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
'import/first': 'error',
'import/no-duplicates': 'error',
'import/no-mutable-exports': 'error',
'import/no-named-default': 'error',
'erasable-syntax-only/enums': 'error',
'erasable-syntax-only/import-aliases': 'error',
'erasable-syntax-only/namespaces': 'error',
'erasable-syntax-only/parameter-properties': 'error',
'regexp/confusing-quantifier': 'warn',
'regexp/control-character-escape': 'error',
'regexp/match-any': 'error',
'regexp/negation': 'error',
'regexp/no-contradiction-with-assertion': 'error',
'regexp/no-dupe-characters-character-class': 'error',
'regexp/no-dupe-disjunctions': 'error',
'regexp/no-empty-alternative': 'warn',
'regexp/no-empty-capturing-group': 'error',
'regexp/no-empty-character-class': 'error',
'regexp/no-empty-group': 'error',
'regexp/no-empty-lookarounds-assertion': 'error',
'regexp/no-empty-string-literal': 'error',
'regexp/no-escape-backspace': 'error',
'regexp/no-extra-lookaround-assertions': 'error',
'regexp/no-invalid-regexp': 'error',
'regexp/no-invisible-character': 'error',
'regexp/no-lazy-ends': 'warn',
'regexp/no-legacy-features': 'error',
'regexp/no-misleading-capturing-group': 'error',
'regexp/no-misleading-unicode-character': 'error',
'regexp/no-missing-g-flag': 'error',
'regexp/no-non-standard-flag': 'error',
'regexp/no-obscure-range': 'error',
'regexp/no-optional-assertion': 'error',
'regexp/no-potentially-useless-backreference': 'warn',
'regexp/no-super-linear-backtracking': 'error',
'regexp/no-trivially-nested-assertion': 'error',
'regexp/no-trivially-nested-quantifier': 'error',
'regexp/no-unused-capturing-group': 'error',
'regexp/no-useless-assertions': 'error',
'regexp/no-useless-backreference': 'error',
'regexp/no-useless-character-class': 'error',
'regexp/no-useless-dollar-replacements': 'error',
'regexp/no-useless-escape': 'error',
'regexp/no-useless-flag': 'warn',
'regexp/no-useless-lazy': 'error',
'regexp/no-useless-non-capturing-group': 'error',
'regexp/no-useless-quantifier': 'error',
'regexp/no-useless-range': 'error',
'regexp/no-useless-set-operand': 'error',
'regexp/no-useless-string-literal': 'error',
'regexp/no-useless-two-nums-quantifier': 'error',
'regexp/no-zero-quantifier': 'error',
'regexp/optimal-lookaround-quantifier': 'warn',
'regexp/optimal-quantifier-concatenation': 'error',
'regexp/prefer-character-class': 'error',
'regexp/prefer-d': 'error',
'regexp/prefer-plus-quantifier': 'error',
'regexp/prefer-predefined-assertion': 'error',
'regexp/prefer-question-quantifier': 'error',
'regexp/prefer-range': 'error',
'regexp/prefer-set-operation': 'error',
'regexp/prefer-star-quantifier': 'error',
'regexp/prefer-unicode-codepoint-escapes': 'error',
'regexp/prefer-w': 'error',
'regexp/simplify-set-operations': 'error',
'regexp/sort-flags': 'error',
'regexp/strict': 'error',
'regexp/use-ignore-case': 'error',
'no-undef': 'error',
},
overrides: [
{
files: ['**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'],
rules: {
'node/handle-callback-err': ['error', '^(err|error)$'],
'node/no-exports-assign': 'error',
'node/no-new-require': 'error',
'node/no-path-concat': 'error',
'jsdoc/check-access': 'warn',
'jsdoc/check-property-names': 'warn',
'jsdoc/empty-tags': 'warn',
'jsdoc/implements-on-classes': 'warn',
'jsdoc/no-defaults': 'warn',
'jsdoc/require-param-name': 'warn',
'jsdoc/require-property': 'warn',
'jsdoc/require-property-description': 'warn',
'jsdoc/require-property-name': 'warn',
'jsdoc/require-returns-description': 'warn',
'unicorn/consistent-empty-array-spread': 'error',
'unicorn/error-message': 'error',
'unicorn/escape-case': 'error',
'unicorn/new-for-builtins': 'error',
'unicorn/no-instanceof-builtins': 'error',
'unicorn/no-new-array': 'error',
'unicorn/no-new-buffer': 'error',
'unicorn/prefer-dom-node-text-content': 'error',
'unicorn/prefer-includes': 'error',
'unicorn/prefer-node-protocol': 'error',
'unicorn/prefer-number-properties': 'error',
'unicorn/prefer-string-starts-ends-with': 'error',
'unicorn/prefer-type-error': 'error',
'unicorn/throw-new-error': 'error',
'node-js/no-deprecated-api': 'error',
'node-js/prefer-global/buffer': ['error', 'never'],
'node-js/process-exit-as-throw': 'error',
'jsdoc-js/check-param-names': 'warn',
'jsdoc-js/check-types': 'warn',
'jsdoc-js/no-multi-asterisks': 'warn',
'jsdoc-js/require-returns-check': 'warn',
'jsdoc-js/require-yields-check': 'warn',
},
},
{
files: ['**/*.{ts,cts,mts}', '**/*.tsx'],
rules: {
'constructor-super': 'off',
'getter-return': 'off',
'no-class-assign': 'off',
'no-const-assign': 'off',
'no-dupe-keys': 'off',
'no-func-assign': 'off',
'no-import-assign': 'off',
'no-new-native-nonconstructor': 'off',
'no-obj-calls': 'off',
'no-redeclare': 'off',
'no-setter-return': 'off',
'no-this-before-super': 'off',
'no-unreachable': 'off',
'no-unsafe-negation': 'off',
'no-with': 'off',
'prefer-const': [
'error',
{
destructuring: 'all',
ignoreReadBeforeAssign: true,
},
],
'no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTaggedTemplates: true,
allowTernary: true,
},
],
'no-useless-constructor': 'off',
'no-use-before-define': [
'error',
{
classes: false,
functions: false,
variables: true,
},
],
'typescript/ban-ts-comment': [
'error',
{
'ts-expect-error': 'allow-with-description',
},
],
'typescript/no-duplicate-enum-values': 'error',
'typescript/no-dynamic-delete': 'off',
'typescript/no-empty-object-type': [
'error',
{
allowInterfaces: 'always',
},
],
'typescript/no-explicit-any': 'error',
'typescript/no-extra-non-null-assertion': 'error',
'typescript/no-extraneous-class': 'off',
'typescript/no-invalid-void-type': 'off',
'typescript/no-misused-new': 'error',
'typescript/no-namespace': 'error',
'typescript/no-non-null-asserted-nullish-coalescing': 'error',
'typescript/no-non-null-asserted-optional-chain': 'error',
'typescript/no-non-null-assertion': 'off',
'typescript/no-require-imports': 'error',
'typescript/no-this-alias': 'error',
'typescript/no-unnecessary-type-constraint': 'error',
'typescript/no-unsafe-declaration-merging': 'error',
'typescript/no-unsafe-function-type': 'error',
'typescript/no-wrapper-object-types': 'error',
'typescript/prefer-as-const': 'error',
'typescript/prefer-literal-enum-member': 'error',
'typescript/prefer-namespace-keyword': 'error',
'typescript/triple-slash-reference': 'off',
'typescript/unified-signatures': 'off',
'typescript/consistent-type-definitions': ['error', 'type'],
'typescript/consistent-type-imports': [
'error',
{
disallowTypeAnnotations: false,
fixStyle: 'separate-type-imports',
prefer: 'type-imports',
},
],
'typescript/method-signature-style': ['error', 'property'],
'typescript/no-import-type-side-effects': 'error',
'no-undef': 'off',
'typescript/dot-notation': [
'error',
{
allowKeywords: true,
allowPattern: '',
},
],
},
},
{
files: [
'**/__tests__/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'**/*.spec.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'**/*.test.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'**/*.bench.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'**/*.benchmark.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
],
rules: {
'vitest/consistent-test-it': [
'error',
{
fn: 'it',
withinDescribe: 'it',
},
],
'vitest/no-identical-title': 'error',
'vitest/no-import-node-test': 'error',
'vitest/prefer-hooks-in-order': 'error',
'vitest/prefer-lowercase-title': 'off',
'antfu/no-top-level-await': 'off',
'no-unused-expressions': 'off',
'typescript/explicit-function-return-type': 'off',
'vitest/no-focused-tests': 'error',
},
},
{
files: ['**/scripts/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'],
rules: {
'antfu/no-top-level-await': 'off',
'no-console': 'off',
'typescript/explicit-function-return-type': 'off',
},
},
{
files: [
'**/cli/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'**/cli.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
],
rules: {
'antfu/no-top-level-await': 'off',
'no-console': 'off',
},
excludeFiles: ['cli/**'],
},
{
files: ['**/bin/**/*', '**/bin.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'],
rules: {
'antfu/no-import-dist': 'off',
'antfu/no-import-node-modules-by-path': 'off',
},
},
{
files: ['**/*.d.{ts,cts,mts}'],
rules: {
'eslint-comments/no-unlimited-disable': 'off',
'no-unused-vars': 'off',
},
},
{
files: ['**/*.js', '**/*.cjs'],
rules: {
'typescript/no-require-imports': 'off',
},
},
{
files: [
'**/*.config.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'**/*.config.*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
],
rules: {
'antfu/no-top-level-await': 'off',
'no-console': 'off',
'typescript/explicit-function-return-type': 'off',
},
},
{
files: ['web/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'],
rules: {
'no-barrel-files/no-barrel-files': 'error',
'@tanstack/query/exhaustive-deps': 'error',
'@tanstack/query/no-rest-destructuring': 'warn',
'@tanstack/query/stable-query-client': 'error',
'@tanstack/query/no-unstable-deps': 'error',
'@tanstack/query/infinite-query-property-order': 'error',
'@tanstack/query/no-void-query-fn': 'error',
'@tanstack/query/mutation-property-order': 'error',
'react/exhaustive-deps': 'warn',
'react/no-array-index-key': 'warn',
'react/no-clone-element': 'warn',
'react/no-direct-mutation-state': 'error',
'react/rules-of-hooks': 'error',
'react/jsx-no-comment-textnodes': 'warn',
'react/only-export-components': [
'error',
{
allowConstantExport: true,
allowExportNames: [],
},
],
},
},
{
files: ['web/**/*.tsx'],
rules: {
'jsx-a11y/alt-text': 'error',
'jsx-a11y/anchor-ambiguous-text': 'off',
'jsx-a11y/anchor-has-content': 'error',
'jsx-a11y/anchor-is-valid': 'error',
'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
'jsx-a11y/aria-props': 'error',
'jsx-a11y/aria-proptypes': 'error',
'jsx-a11y/aria-role': 'error',
'jsx-a11y/aria-unsupported-elements': 'error',
'jsx-a11y/autocomplete-valid': 'error',
'jsx-a11y/click-events-have-key-events': 'error',
'jsx-a11y/heading-has-content': 'error',
'jsx-a11y/html-has-lang': 'error',
'jsx-a11y/iframe-has-title': 'error',
'jsx-a11y/img-redundant-alt': 'error',
'jsx-a11y/interactive-supports-focus': [
'error',
{
tabbable: [
'button',
'checkbox',
'link',
'searchbox',
'spinbutton',
'switch',
'textbox',
],
},
],
'jsx-a11y/label-has-associated-control': 'error',
'jsx-a11y/media-has-caption': 'error',
'jsx-a11y/mouse-events-have-key-events': 'error',
'jsx-a11y/no-access-key': 'error',
'jsx-a11y/no-autofocus': 'error',
'jsx-a11y/no-distracting-elements': 'error',
'jsx-a11y/no-interactive-element-to-noninteractive-role': [
'error',
{
tr: ['none', 'presentation'],
canvas: ['img'],
},
],
'jsx-a11y/no-noninteractive-element-interactions': [
'error',
{
handlers: [
'onClick',
'onError',
'onLoad',
'onMouseDown',
'onMouseUp',
'onKeyPress',
'onKeyDown',
'onKeyUp',
],
alert: ['onKeyUp', 'onKeyDown', 'onKeyPress'],
body: ['onError', 'onLoad'],
dialog: ['onKeyUp', 'onKeyDown', 'onKeyPress'],
iframe: ['onError', 'onLoad'],
img: ['onError', 'onLoad'],
},
],
'jsx-a11y/no-noninteractive-element-to-interactive-role': [
'error',
{
ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
li: [
'menuitem',
'menuitemradio',
'menuitemcheckbox',
'option',
'row',
'tab',
'treeitem',
],
table: ['grid'],
td: ['gridcell'],
fieldset: ['radiogroup', 'presentation'],
},
],
'jsx-a11y/no-noninteractive-tabindex': [
'error',
{
tags: [],
roles: ['tabpanel'],
allowExpressionValues: true,
},
],
'jsx-a11y/no-redundant-roles': 'error',
'jsx-a11y/no-static-element-interactions': [
'error',
{
allowExpressionValues: true,
handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'],
},
],
'jsx-a11y/role-has-required-aria-props': 'error',
'jsx-a11y/role-supports-aria-props': 'error',
'jsx-a11y/scope': 'error',
'jsx-a11y/tabindex-no-positive': 'error',
},
},
{
files: ['web/**/*.stories.{js,cjs,mjs,jsx,ts,tsx}', 'web/**/*.story.{js,cjs,mjs,jsx,ts,tsx}'],
rules: {
'storybook/await-interactions': 'error',
'storybook/context-in-play-function': 'error',
'storybook/default-exports': 'error',
'storybook/hierarchy-separator': 'warn',
'storybook/no-redundant-story-name': 'warn',
'storybook/no-renderer-packages': 'error',
'storybook/prefer-pascal-case': 'warn',
'storybook/story-exports': 'error',
'storybook/use-storybook-expect': 'error',
'storybook/use-storybook-testing-library': 'error',
'import/no-anonymous-default-export': 'off',
'react/rules-of-hooks': 'off',
},
},
{
files: ['web/.storybook/main.{js,cjs,mjs,ts}'],
rules: {
'storybook/no-uninstalled-addons': 'error',
},
},
{
files: ['web/**/*.tsx'],
rules: {
'hyoban/prefer-tailwind-icons': [
'warn',
{
prefix: 'i-',
propMappings: {
size: 'size',
width: 'w',
height: 'h',
},
libraries: [
{
prefix: 'i-custom-',
source: '^@/app/components/base/icons/src/(?<set>(?:public|vender)(?:/.*)?)$',
name: '^(?<name>.*)$',
},
{
source: '^@remixicon/react$',
name: '^(?<set>Ri)(?<name>.+)$',
},
{
source: '^@(?<set>heroicons)/react/24/outline$',
name: '^(?<name>.*)Icon$',
},
{
source: '^@(?<set>heroicons)/react/24/(?<variant>solid)$',
name: '^(?<name>.*)Icon$',
},
{
source: '^@(?<set>heroicons)/react/(?<variant>\\d+/(?:solid|outline))$',
name: '^(?<name>.*)Icon$',
},
],
},
],
},
},
{
files: ['web/**/*.{ts,cts,mts}', 'web/**/*.tsx'],
rules: {
'no-restricted-imports': [
'error',
{
paths: [
{
name: 'next',
message: 'Import Next APIs from the corresponding @/next module instead of next.',
},
{
name: 'ahooks',
importNames: ['useLocalStorageState'],
message:
'Do not use ahooks useLocalStorageState. Use foxact storage hooks instead.',
},
],
patterns: [
{
group: ['next/image'],
message: 'Do not import next/image. Use native img tags instead.',
},
{
group: ['next/font', 'next/font/*'],
message: 'Do not import next/font. Use the project font styles instead.',
},
{
group: ['next/*', '!next/font', '!next/font/*', '!next/image', '!next/image/*'],
message:
'Import Next APIs from the corresponding @/next/* module instead of next/*.',
},
{
group: ['@base-ui/react', '@base-ui/react/*'],
message:
'Do not import Base UI directly in web. Use @langgenius/dify-ui/* primitives instead.',
},
{
group: ['@floating-ui/*'],
message:
'Do not import Floating UI directly in web. Use @langgenius/dify-ui/* primitives instead.',
},
{
group: ['**/base/input', '**/base/input/*'],
message:
'Do not import the deprecated web base Input. Use @langgenius/dify-ui/input for standalone inputs, and @langgenius/dify-ui/field for labelled or validated form composition.',
},
{
group: [
'@/service/base',
'@/service/base/*',
'**/service/base',
'**/service/base/*',
],
message:
'Do not import legacy service/base fetch helpers. Use generated service clients or feature-specific service modules instead.',
},
{
group: [
'@/service/fetch',
'@/service/fetch/*',
'**/service/fetch',
'**/service/fetch/*',
],
message:
'Do not import low-level service/fetch helpers directly. Use generated service clients or feature-specific service modules instead.',
},
],
},
],
},
},
{
files: ['web/service/**/*.ts', 'web/service/**/*.tsx'],
rules: {
'no-restricted-imports': [
'error',
{
paths: [
{
name: 'next',
message: 'Import Next APIs from the corresponding @/next module instead of next.',
},
{
name: 'ahooks',
importNames: ['useLocalStorageState'],
message:
'Do not use ahooks useLocalStorageState. Use foxact storage hooks instead.',
},
],
patterns: [
{
group: ['next/image'],
message: 'Do not import next/image. Use native img tags instead.',
},
{
group: ['next/font', 'next/font/*'],
message: 'Do not import next/font. Use the project font styles instead.',
},
{
group: ['next/*', '!next/font', '!next/font/*', '!next/image', '!next/image/*'],
message:
'Import Next APIs from the corresponding @/next/* module instead of next/*.',
},
{
group: ['@base-ui/react', '@base-ui/react/*'],
message:
'Do not import Base UI directly in web. Use @langgenius/dify-ui/* primitives instead.',
},
{
group: ['@floating-ui/*'],
message:
'Do not import Floating UI directly in web. Use @langgenius/dify-ui/* primitives instead.',
},
{
group: ['**/base/input', '**/base/input/*'],
message:
'Do not import the deprecated web base Input. Use @langgenius/dify-ui/input for standalone inputs, and @langgenius/dify-ui/field for labelled or validated form composition.',
},
{
group: [
'@/service/base',
'@/service/base/*',
'**/service/base',
'**/service/base/*',
],
message:
'Do not import legacy service/base fetch helpers. Use generated service clients or feature-specific service modules instead.',
},
{
group: [
'@/service/fetch',
'@/service/fetch/*',
'**/service/fetch',
'**/service/fetch/*',
],
message:
'Do not import low-level service/fetch helpers directly. Use generated service clients or feature-specific service modules instead.',
},
{
group: ['./base', './base/*', '../base', '../base/*', '../../base', '../../base/*'],
message:
'Do not import legacy service/base fetch helpers. Use generated service clients or feature-specific service modules instead.',
},
{
group: [
'./fetch',
'./fetch/*',
'../fetch',
'../fetch/*',
'../../fetch',
'../../fetch/*',
],
message:
'Do not import low-level service/fetch helpers directly. Use generated service clients or feature-specific service modules instead.',
},
],
},
],
},
},
{
files: ['web/**/*.{ts,cts,mts}', 'web/**/*.tsx'],
excludeFiles: [
'web/**/__tests__/**',
'web/**/*.spec.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'web/**/*.test.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'web/**/*.bench.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'web/**/*.benchmark.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'web/vitest.setup.ts',
'web/instrumentation-client.ts',
],
rules: {
'no-restricted-globals': [
'error',
{
name: 'localStorage',
message:
'Do not use localStorage directly. Use a foxact storage boundary instead; prefer feature-owned createLocalStorageState for shared storage.',
},
],
'no-restricted-properties': [
'error',
{
object: 'window',
property: 'localStorage',
message:
'Do not use window.localStorage directly. Use a foxact storage boundary instead; prefer feature-owned createLocalStorageState for shared storage.',
},
{
object: 'globalThis',
property: 'localStorage',
message:
'Do not use globalThis.localStorage directly. Use a foxact storage boundary instead; prefer feature-owned createLocalStorageState for shared storage.',
},
],
},
},
{
files: [
'web/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'packages/dify-ui/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
],
rules: {
'eslint-react/no-children-count': 'warn',
'eslint-react/no-children-for-each': 'warn',
'eslint-react/no-children-map': 'warn',
'eslint-react/no-children-only': 'warn',
'eslint-react/no-children-to-array': 'warn',
'eslint-react/no-component-will-mount': 'error',
'eslint-react/no-component-will-receive-props': 'error',
'eslint-react/no-component-will-update': 'error',
'eslint-react/no-context-provider': 'warn',
'eslint-react/no-create-ref': 'error',
'eslint-react/no-forward-ref': 'warn',
'eslint-react/no-missing-key': 'error',
'eslint-react/no-nested-component-definitions': 'error',
'eslint-react/no-nested-lazy-component-declarations': 'error',
'eslint-react/no-set-state-in-component-did-mount': 'warn',
'eslint-react/no-set-state-in-component-did-update': 'warn',
'eslint-react/no-set-state-in-component-will-update': 'warn',
'eslint-react/no-unnecessary-use-prefix': 'error',
'eslint-react/no-unsafe-component-will-mount': 'warn',
'eslint-react/no-unsafe-component-will-receive-props': 'warn',
'eslint-react/no-unsafe-component-will-update': 'warn',
'eslint-react/no-unused-class-component-members': 'warn',
'eslint-react/no-use-context': 'warn',
'eslint-react/use-state': 'warn',
'eslint-react/jsx-no-children-prop': 'warn',
'eslint-react/jsx-no-children-prop-with-children': 'error',
'eslint-react/jsx-no-key-after-spread': 'error',
'eslint-react/jsx-no-leaked-dollar': 'warn',
'eslint-react/jsx-no-leaked-semicolon': 'warn',
'eslint-react/jsx-no-namespace': 'error',
'eslint-react/rsc-function-definition': 'error',
'eslint-react/dom-no-dangerously-set-innerhtml': 'warn',
'eslint-react/dom-no-dangerously-set-innerhtml-with-children': 'error',
'eslint-react/dom-no-find-dom-node': 'error',
'eslint-react/dom-no-flush-sync': 'error',
'eslint-react/dom-no-hydrate': 'error',
'eslint-react/dom-no-render': 'error',
'eslint-react/dom-no-render-return-value': 'error',
'eslint-react/dom-no-script-url': 'warn',
'eslint-react/dom-no-unsafe-iframe-sandbox': 'warn',
'eslint-react/dom-no-use-form-state': 'error',
'eslint-react/dom-no-void-elements-with-children': 'error',
'eslint-react/web-api-no-leaked-event-listener': 'warn',
'eslint-react/web-api-no-leaked-fetch': 'warn',
'eslint-react/web-api-no-leaked-intersection-observer': 'warn',
'eslint-react/web-api-no-leaked-interval': 'warn',
'eslint-react/web-api-no-leaked-resize-observer': 'warn',
'eslint-react/web-api-no-leaked-timeout': 'warn',
'eslint-react/naming-convention-context-name': 'warn',
'eslint-react/naming-convention-id-name': 'warn',
'eslint-react/naming-convention-ref-name': 'warn',
'eslint-react/error-boundaries': 'error',
'eslint-react/no-access-state-in-setstate': 'error',
'eslint-react/purity': 'warn',
'eslint-react/set-state-in-effect': 'error',
'eslint-react/set-state-in-render': 'error',
'eslint-react/static-components': 'error',
'eslint-react/unsupported-syntax': 'error',
'eslint-react/use-memo': 'error',
},
},
{
files: [
'web/**/__tests__/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'web/**/*.spec.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'web/**/*.test.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'web/vitest.setup.ts',
'web/test/i18n-mock.ts',
],
rules: {
'eslint-react/no-unnecessary-use-prefix': 'off',
},
},
{
files: ['packages/dify-ui/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'],
rules: {
'react/exhaustive-deps': [
'error',
{
additionalHooks: 'useIsoLayoutEffect',
},
],
'react/no-array-index-key': 'warn',
'react/no-clone-element': 'warn',
'react/no-direct-mutation-state': 'error',
'react/rules-of-hooks': 'error',
'react/jsx-no-comment-textnodes': 'warn',
'react/only-export-components': 'off',
'eslint-react/no-context-provider': 'off',
'eslint-react/no-use-context': 'off',
},
},
{
files: ['packages/dify-ui/**/*.tsx'],
rules: {
'jsx-a11y/alt-text': 'error',
'jsx-a11y/anchor-ambiguous-text': 'off',
'jsx-a11y/anchor-has-content': 'off',
'jsx-a11y/anchor-is-valid': 'error',
'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
'jsx-a11y/aria-props': 'error',
'jsx-a11y/aria-proptypes': 'error',
'jsx-a11y/aria-role': 'error',
'jsx-a11y/aria-unsupported-elements': 'error',
'jsx-a11y/autocomplete-valid': 'error',
'jsx-a11y/click-events-have-key-events': 'error',
'jsx-a11y/control-has-associated-label': 'off',
'jsx-a11y/heading-has-content': 'error',
'jsx-a11y/html-has-lang': 'error',
'jsx-a11y/iframe-has-title': 'error',
'jsx-a11y/img-redundant-alt': 'error',
'jsx-a11y/interactive-supports-focus': [
'error',
{
tabbable: [
'button',
'checkbox',
'link',
'searchbox',
'spinbutton',
'switch',
'textbox',
],
},
],
'jsx-a11y/label-has-associated-control': 'off',
'jsx-a11y/media-has-caption': 'error',
'jsx-a11y/mouse-events-have-key-events': 'error',
'jsx-a11y/no-access-key': 'error',
'jsx-a11y/no-autofocus': 'error',
'jsx-a11y/no-distracting-elements': 'error',
'jsx-a11y/no-interactive-element-to-noninteractive-role': [
'error',
{
tr: ['none', 'presentation'],
canvas: ['img'],
},
],
'jsx-a11y/no-noninteractive-element-interactions': [
'error',
{
handlers: [
'onClick',
'onError',
'onLoad',
'onMouseDown',
'onMouseUp',
'onKeyPress',
'onKeyDown',
'onKeyUp',
],
alert: ['onKeyUp', 'onKeyDown', 'onKeyPress'],
body: ['onError', 'onLoad'],
dialog: ['onKeyUp', 'onKeyDown', 'onKeyPress'],
iframe: ['onError', 'onLoad'],
img: ['onError', 'onLoad'],
},
],
'jsx-a11y/no-noninteractive-element-to-interactive-role': [
'error',
{
ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'],
li: [
'menuitem',
'menuitemradio',
'menuitemcheckbox',
'option',
'row',
'tab',
'treeitem',
],
table: ['grid'],
td: ['gridcell'],
fieldset: ['radiogroup', 'presentation'],
},
],
'jsx-a11y/no-noninteractive-tabindex': [
'error',
{
tags: [],
roles: ['tabpanel'],
allowExpressionValues: true,
},
],
'jsx-a11y/no-redundant-roles': 'error',
'jsx-a11y/no-static-element-interactions': [
'error',
{
allowExpressionValues: true,
handlers: ['onClick', 'onMouseDown', 'onMouseUp', 'onKeyPress', 'onKeyDown', 'onKeyUp'],
},
],
'jsx-a11y/role-has-required-aria-props': 'error',
'jsx-a11y/role-supports-aria-props': 'error',
'jsx-a11y/scope': 'error',
'jsx-a11y/tabindex-no-positive': 'error',
},
},
{
files: [
'packages/dify-ui/**/*.stories.{js,cjs,mjs,jsx,ts,tsx}',
'packages/dify-ui/**/*.story.{js,cjs,mjs,jsx,ts,tsx}',
],
rules: {
'storybook/await-interactions': 'error',
'storybook/context-in-play-function': 'error',
'storybook/default-exports': 'error',
'storybook/hierarchy-separator': 'warn',
'storybook/no-redundant-story-name': 'warn',
'storybook/no-renderer-packages': 'error',
'storybook/prefer-pascal-case': 'warn',
'storybook/story-exports': 'error',
'storybook/use-storybook-expect': 'error',
'storybook/use-storybook-testing-library': 'error',
'import/no-anonymous-default-export': 'off',
'react/rules-of-hooks': 'off',
},
},
{
files: ['packages/dify-ui/**/.storybook/main.{js,cjs,mjs,ts}'],
rules: {
'storybook/no-uninstalled-addons': [
'error',
{
packageJsonLocation: difyUiPackageJson,
},
],
},
},
{
files: [
'packages/dify-ui/**/__tests__/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
'packages/dify-ui/**/*.spec.{js,cjs,mjs,jsx,ts,cts,mts,tsx}',
],
rules: {
'eslint-react/purity': 'off',
},
},
{
files: ['cli/bin/**'],
rules: {
'antfu/no-top-level-await': 'off',
},
},
{
files: ['cli/src/**/*.ts'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['../**', './*/**', '..'],
message:
'Use the @/ (or @test/) alias for parent-directory or nested relative imports; keep ./ only for same-folder siblings.',
},
],
},
],
},
},
{
files: ['sdks/nodejs-client/src/**/*.ts', 'sdks/nodejs-client/tests/**/*.ts'],
rules: {
'accessor-pairs': 'off',
'antfu/no-top-level-await': 'off',
'array-callback-return': 'off',
'block-scoped-var': 'off',
'constructor-super': 'error',
'default-case-last': 'off',
eqeqeq: 'off',
'new-cap': 'off',
'no-alert': 'off',
'no-array-constructor': 'error',
'no-async-promise-executor': 'error',
'no-caller': 'off',
'no-case-declarations': 'error',
'no-class-assign': 'error',
'no-compare-neg-zero': 'error',
'no-cond-assign': 'error',
'no-console': 'off',
'no-const-assign': 'error',
'no-control-regex': 'off',
'no-debugger': 'error',
'no-delete-var': 'error',
'no-dupe-class-members': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-empty': 'error',
'no-empty-pattern': 'error',
'no-eval': 'off',
'no-ex-assign': 'error',
'no-extend-native': 'off',
'no-extra-bind': 'off',
'no-extra-boolean-cast': 'error',
'no-fallthrough': 'error',
'no-func-assign': 'error',
'no-global-assign': 'error',
'no-implied-eval': 'off',
'no-import-assign': 'error',
'no-irregular-whitespace': 'error',
'no-iterator': 'off',
'no-labels': 'off',
'no-lone-blocks': 'off',
'no-loss-of-precision': 'error',
'no-misleading-character-class': 'error',
'no-multi-str': 'off',
'no-new': 'off',
'no-new-func': 'off',
'no-new-native-nonconstructor': 'error',
'no-new-wrappers': 'off',
'no-obj-calls': 'error',
'no-proto': 'off',
'no-prototype-builtins': 'error',
'no-redeclare': 'error',
'no-regex-spaces': 'error',
'no-restricted-globals': 'off',
'no-restricted-properties': 'off',
'no-self-assign': 'error',
'no-self-compare': 'off',
'no-sequences': 'off',
'no-shadow-restricted-names': 'error',
'no-sparse-arrays': 'error',
'no-template-curly-in-string': 'off',
'no-this-before-super': 'error',
'no-throw-literal': 'off',
'no-unexpected-multiline': 'error',
'no-unmodified-loop-condition': 'off',
'no-unneeded-ternary': 'off',
'no-unreachable': 'error',
'no-unsafe-finally': 'error',
'no-unsafe-negation': 'error',
'no-unused-expressions': 'error',
'no-unused-vars': 'error',
'no-use-before-define': 'off',
'no-useless-call': 'off',
'no-useless-catch': 'error',
'no-useless-computed-key': 'off',
'no-useless-constructor': 'off',
'no-useless-rename': 'off',
'no-useless-return': 'off',
'no-var': 'off',
'no-with': 'error',
'object-shorthand': 'off',
'prefer-arrow-callback': 'off',
'prefer-const': 'off',
'prefer-exponentiation-operator': 'off',
'prefer-promise-reject-errors': 'off',
'prefer-regex-literals': 'off',
'prefer-rest-params': 'off',
'prefer-spread': 'off',
'prefer-template': 'off',
'symbol-description': 'off',
'unicode-bom': 'off',
'use-isnan': 'error',
'valid-typeof': 'error',
'vars-on-top': 'off',
yoda: 'off',
'eslint-comments/no-aggregating-enable': 'off',
'eslint-comments/no-duplicate-disable': 'off',
'eslint-comments/no-unlimited-disable': 'off',
'eslint-comments/no-unused-enable': 'off',
'command/command': 'off',
'perfectionist/sort-exports': 'off',
'perfectionist/sort-named-exports': 'off',
'perfectionist/sort-named-imports': 'off',
'antfu/import-dedupe': 'off',
'antfu/no-import-dist': 'off',
'antfu/no-import-node-modules-by-path': 'off',
'import/consistent-type-specifier-style': 'off',
'import/first': 'off',
'import/no-duplicates': 'off',
'import/no-mutable-exports': 'off',
'import/no-named-default': 'off',
'erasable-syntax-only/enums': 'off',
'erasable-syntax-only/import-aliases': 'off',
'erasable-syntax-only/namespaces': 'off',
'erasable-syntax-only/parameter-properties': 'off',
'regexp/confusing-quantifier': 'off',
'regexp/control-character-escape': 'off',
'regexp/match-any': 'off',
'regexp/negation': 'off',
'regexp/no-contradiction-with-assertion': 'off',
'regexp/no-dupe-characters-character-class': 'off',
'regexp/no-dupe-disjunctions': 'off',
'regexp/no-empty-alternative': 'off',
'regexp/no-empty-capturing-group': 'off',
'regexp/no-empty-character-class': 'off',
'regexp/no-empty-group': 'off',
'regexp/no-empty-lookarounds-assertion': 'off',
'regexp/no-empty-string-literal': 'off',
'regexp/no-escape-backspace': 'off',
'regexp/no-extra-lookaround-assertions': 'off',
'regexp/no-invalid-regexp': 'off',
'regexp/no-invisible-character': 'off',
'regexp/no-lazy-ends': 'off',
'regexp/no-legacy-features': 'off',
'regexp/no-misleading-capturing-group': 'off',
'regexp/no-misleading-unicode-character': 'off',
'regexp/no-missing-g-flag': 'off',
'regexp/no-non-standard-flag': 'off',
'regexp/no-obscure-range': 'off',
'regexp/no-optional-assertion': 'off',
'regexp/no-potentially-useless-backreference': 'off',
'regexp/no-super-linear-backtracking': 'off',
'regexp/no-trivially-nested-assertion': 'off',
'regexp/no-trivially-nested-quantifier': 'off',
'regexp/no-unused-capturing-group': 'off',
'regexp/no-useless-assertions': 'off',
'regexp/no-useless-backreference': 'off',
'regexp/no-useless-character-class': 'off',
'regexp/no-useless-dollar-replacements': 'off',
'regexp/no-useless-escape': 'off',
'regexp/no-useless-flag': 'off',
'regexp/no-useless-lazy': 'off',
'regexp/no-useless-non-capturing-group': 'off',
'regexp/no-useless-quantifier': 'off',
'regexp/no-useless-range': 'off',
'regexp/no-useless-set-operand': 'off',
'regexp/no-useless-string-literal': 'off',
'regexp/no-useless-two-nums-quantifier': 'off',
'regexp/no-zero-quantifier': 'off',
'regexp/optimal-lookaround-quantifier': 'off',
'regexp/optimal-quantifier-concatenation': 'off',
'regexp/prefer-character-class': 'off',
'regexp/prefer-d': 'off',
'regexp/prefer-plus-quantifier': 'off',
'regexp/prefer-predefined-assertion': 'off',
'regexp/prefer-question-quantifier': 'off',
'regexp/prefer-range': 'off',
'regexp/prefer-set-operation': 'off',
'regexp/prefer-star-quantifier': 'off',
'regexp/prefer-unicode-codepoint-escapes': 'off',
'regexp/prefer-w': 'off',
'regexp/simplify-set-operations': 'off',
'regexp/sort-flags': 'off',
'regexp/strict': 'off',
'regexp/use-ignore-case': 'off',
'no-undef': 'off',
'node/handle-callback-err': 'off',
'node/no-exports-assign': 'off',
'node/no-new-require': 'off',
'node/no-path-concat': 'off',
'jsdoc/check-access': 'off',
'jsdoc/check-property-names': 'off',
'jsdoc/empty-tags': 'off',
'jsdoc/implements-on-classes': 'off',
'jsdoc/no-defaults': 'off',
'jsdoc/require-param-name': 'off',
'jsdoc/require-property': 'off',
'jsdoc/require-property-description': 'off',
'jsdoc/require-property-name': 'off',
'jsdoc/require-returns-description': 'off',
'unicorn/consistent-empty-array-spread': 'off',
'unicorn/error-message': 'off',
'unicorn/escape-case': 'off',
'unicorn/new-for-builtins': 'off',
'unicorn/no-instanceof-builtins': 'off',
'unicorn/no-new-array': 'off',
'unicorn/no-new-buffer': 'off',
'unicorn/prefer-dom-node-text-content': 'off',
'unicorn/prefer-includes': 'off',
'unicorn/prefer-node-protocol': 'off',
'unicorn/prefer-number-properties': 'off',
'unicorn/prefer-string-starts-ends-with': 'off',
'unicorn/prefer-type-error': 'off',
'unicorn/throw-new-error': 'off',
'node-js/no-deprecated-api': 'off',
'node-js/prefer-global/buffer': 'off',
'node-js/process-exit-as-throw': 'off',
'jsdoc-js/check-param-names': 'off',
'jsdoc-js/check-types': 'off',
'jsdoc-js/no-multi-asterisks': 'off',
'jsdoc-js/require-returns-check': 'off',
'jsdoc-js/require-yields-check': 'off',
'getter-return': 'error',
'no-setter-return': 'error',
'typescript/ban-ts-comment': 'error',
'typescript/no-duplicate-enum-values': 'error',
'typescript/no-dynamic-delete': 'off',
'typescript/no-empty-object-type': 'error',
'typescript/no-explicit-any': 'error',
'typescript/no-extra-non-null-assertion': 'error',
'typescript/no-extraneous-class': 'off',
'typescript/no-invalid-void-type': 'off',
'typescript/no-misused-new': 'error',
'typescript/no-namespace': 'error',
'typescript/no-non-null-asserted-nullish-coalescing': 'off',
'typescript/no-non-null-asserted-optional-chain': 'error',
'typescript/no-non-null-assertion': 'off',
'typescript/no-require-imports': 'error',
'typescript/no-this-alias': 'error',
'typescript/no-unnecessary-type-constraint': 'error',
'typescript/no-unsafe-declaration-merging': 'error',
'typescript/no-unsafe-function-type': 'error',
'typescript/no-wrapper-object-types': 'error',
'typescript/prefer-as-const': 'error',
'typescript/prefer-literal-enum-member': 'off',
'typescript/prefer-namespace-keyword': 'error',
'typescript/triple-slash-reference': 'error',
'typescript/unified-signatures': 'off',
'typescript/consistent-type-definitions': 'off',
'typescript/consistent-type-imports': [
'error',
{
prefer: 'type-imports',
fixStyle: 'separate-type-imports',
},
],
'typescript/method-signature-style': 'off',
'typescript/no-import-type-side-effects': 'off',
'typescript/dot-notation': 'off',
'vitest/consistent-test-it': 'off',
'vitest/no-identical-title': 'off',
'vitest/no-import-node-test': 'off',
'vitest/prefer-hooks-in-order': 'off',
'vitest/prefer-lowercase-title': 'off',
'typescript/explicit-function-return-type': 'off',
'vitest/no-focused-tests': 'off',
'for-direction': 'error',
'no-constant-binary-expression': 'error',
'no-constant-condition': 'error',
'no-dupe-else-if': 'error',
'no-empty-character-class': 'error',
'no-empty-static-block': 'error',
'no-invalid-regexp': 'error',
'no-nonoctal-decimal-escape': 'error',
'no-unassigned-vars': 'error',
'no-unsafe-optional-chaining': 'error',
'no-unused-labels': 'error',
'no-unused-private-class-members': 'error',
'no-useless-backreference': 'error',
'no-useless-escape': 'error',
'preserve-caught-error': 'error',
'require-yield': 'error',
'require-await': 'off',
'typescript/await-thenable': 'error',
'typescript/no-array-delete': 'error',
'typescript/no-base-to-string': 'error',
'typescript/no-duplicate-type-constituents': 'error',
'typescript/no-floating-promises': 'error',
'typescript/no-for-in-array': 'error',
'typescript/no-implied-eval': 'error',
'typescript/no-misused-promises': 'error',
'typescript/no-redundant-type-constituents': 'error',
'typescript/no-unnecessary-type-assertion': 'error',
'typescript/no-unsafe-argument': 'error',
'typescript/no-unsafe-assignment': 'error',
'typescript/no-unsafe-call': 'error',
'typescript/no-unsafe-enum-comparison': 'error',
'typescript/no-unsafe-member-access': 'error',
'typescript/no-unsafe-return': 'error',
'typescript/no-unsafe-unary-minus': 'error',
'typescript/only-throw-error': 'error',
'typescript/prefer-promise-reject-errors': 'error',
'typescript/require-await': 'error',
'typescript/restrict-plus-operands': 'error',
'typescript/restrict-template-expressions': 'error',
'typescript/unbound-method': 'error',
'no-useless-assignment': 'error',
},
},
],
} satisfies OxlintConfig