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/(?(?:public|vender)(?:/.*)?)$', name: '^(?.*)$', }, { source: '^@remixicon/react$', name: '^(?Ri)(?.+)$', }, { source: '^@(?heroicons)/react/24/outline$', name: '^(?.*)Icon$', }, { source: '^@(?heroicons)/react/24/(?solid)$', name: '^(?.*)Icon$', }, { source: '^@(?heroicons)/react/(?\\d+/(?:solid|outline))$', 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