dify/eslint.config.mjs
2026-07-13 08:00:39 +00:00

434 lines
11 KiB
JavaScript

// @ts-check
import markdown from '@eslint/markdown'
import md from 'eslint-markdown'
import hyoban from 'eslint-plugin-hyoban'
import jsonc from 'eslint-plugin-jsonc'
import markdownPreferences from 'eslint-plugin-markdown-preferences'
import pnpm from 'eslint-plugin-pnpm'
import toml from 'eslint-plugin-toml'
import yml from 'eslint-plugin-yml'
import { defineConfig, globalIgnores } from 'eslint/config'
import dify from './web/plugins/eslint/index.js'
const codeFiles = '**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'
const mdPlugin = /** @type {import('eslint').ESLint.Plugin} */ (/** @type {unknown} */ (md))
/**
* Migration tradeoff: ESLint is intentionally restricted to non-code files.
*
* Disabled code-only checks:
* - Core: `no-control-regex`, `no-octal`, `no-octal-escape`, `no-undef-init`,
* `no-unreachable-loop`, and `one-var`.
* - JavaScript: `dot-notation`.
* - Declarations: the former 223-rule snapshot and CLI `no-restricted-imports` override.
* - Dify UI: the three `better-tailwindcss` rules and stricter unused-directive severity.
*
* These checks are documentation only and do not appear in the executable config below.
*/
const tsconfigCompilerOptionsOrder = [
'incremental',
'composite',
'tsBuildInfoFile',
'disableSourceOfProjectReferenceRedirect',
'disableSolutionSearching',
'disableReferencedProjectLoad',
'target',
'jsx',
'jsxFactory',
'jsxFragmentFactory',
'jsxImportSource',
'lib',
'moduleDetection',
'noLib',
'reactNamespace',
'useDefineForClassFields',
'emitDecoratorMetadata',
'experimentalDecorators',
'libReplacement',
'baseUrl',
'rootDir',
'rootDirs',
'customConditions',
'module',
'moduleResolution',
'moduleSuffixes',
'noResolve',
'paths',
'resolveJsonModule',
'resolvePackageJsonExports',
'resolvePackageJsonImports',
'typeRoots',
'types',
'allowArbitraryExtensions',
'allowImportingTsExtensions',
'allowUmdGlobalAccess',
'allowJs',
'checkJs',
'maxNodeModuleJsDepth',
'strict',
'strictBindCallApply',
'strictFunctionTypes',
'strictNullChecks',
'strictPropertyInitialization',
'allowUnreachableCode',
'allowUnusedLabels',
'alwaysStrict',
'exactOptionalPropertyTypes',
'noFallthroughCasesInSwitch',
'noImplicitAny',
'noImplicitOverride',
'noImplicitReturns',
'noImplicitThis',
'noPropertyAccessFromIndexSignature',
'noUncheckedIndexedAccess',
'noUnusedLocals',
'noUnusedParameters',
'useUnknownInCatchVariables',
'declaration',
'declarationDir',
'declarationMap',
'downlevelIteration',
'emitBOM',
'emitDeclarationOnly',
'importHelpers',
'importsNotUsedAsValues',
'inlineSourceMap',
'inlineSources',
'mapRoot',
'newLine',
'noEmit',
'noEmitHelpers',
'noEmitOnError',
'outDir',
'outFile',
'preserveConstEnums',
'preserveValueImports',
'removeComments',
'sourceMap',
'sourceRoot',
'stripInternal',
'allowSyntheticDefaultImports',
'esModuleInterop',
'forceConsistentCasingInFileNames',
'isolatedDeclarations',
'isolatedModules',
'preserveSymlinks',
'verbatimModuleSyntax',
'erasableSyntaxOnly',
'skipDefaultLibCheck',
'skipLibCheck',
]
const pnpmWorkspaceOrder = [
'cacheDir',
'catalogMode',
'cleanupUnusedCatalogs',
'dedupeDirectDeps',
'deployAllFiles',
'enablePrePostScripts',
'engineStrict',
'extendNodePath',
'hoist',
'hoistPattern',
'hoistWorkspacePackages',
'ignoreCompatibilityDb',
'ignoreDepScripts',
'ignoreScripts',
'ignoreWorkspaceRootCheck',
'managePackageManagerVersions',
'minimumReleaseAge',
'minimumReleaseAgeExclude',
'modulesDir',
'nodeLinker',
'nodeVersion',
'optimisticRepeatInstall',
'packageManagerStrict',
'packageManagerStrictVersion',
'preferSymlinkedExecutables',
'preferWorkspacePackages',
'publicHoistPattern',
'registrySupportsTimeField',
'requiredScripts',
'resolutionMode',
'savePrefix',
'scriptShell',
'shamefullyHoist',
'shellEmulator',
'stateDir',
'supportedArchitectures',
'symlink',
'tag',
'trustPolicy',
'trustPolicyExclude',
'updateNotifier',
'packages',
'overrides',
'patchedDependencies',
'catalog',
'catalogs',
'allowedDeprecatedVersions',
'allowNonAppliedPatches',
'configDependencies',
'ignoredBuiltDependencies',
'ignoredOptionalDependencies',
'neverBuiltDependencies',
'onlyBuiltDependencies',
'onlyBuiltDependenciesFile',
'packageExtensions',
'peerDependencyRules',
]
export default defineConfig([
globalIgnores(
[
'**/*',
'!cli/',
'!cli/**/*',
'!e2e/',
'!e2e/**/*',
'!packages/',
'!packages/**/*',
'!sdks/',
'!sdks/nodejs-client/',
'!sdks/nodejs-client/src/',
'!sdks/nodejs-client/src/**/*',
'!sdks/nodejs-client/tests/',
'!sdks/nodejs-client/tests/**/*',
'!web/',
'!web/**/*',
'!eslint.config.mjs',
'!lint.config.ts',
'!package.json',
'!pnpm-workspace.yaml',
'!vite.config.ts',
],
'Project lint scope',
),
globalIgnores([codeFiles], 'Migration tradeoff: code files are handled by Oxlint only'),
globalIgnores(
[
'**/.git/**',
'**/node_modules/**',
'cli/context/**',
'cli/coverage/**',
'cli/dist/**',
'cli/docs/**',
'**/.next/**',
'**/.vinext/**',
'**/coverage/**',
'**/dist/**',
'**/storybook-static/**',
'e2e/.auth/**',
'e2e/cucumber-report/**',
'packages/contracts/**',
'web/next/**',
'web/next-env.d.ts',
'web/public/**',
'web/types/doc-paths.ts',
],
'Generated and external files',
),
{
linterOptions: {
reportUnusedDisableDirectives: 'warn',
},
},
{
files: ['**/*.{json,json5,jsonc}'],
language: 'jsonc/x',
plugins: {
jsonc,
},
rules: {
'no-unused-expressions': 'off',
'no-unused-vars': 'off',
strict: 'off',
'jsonc/no-bigint-literals': 'error',
'jsonc/no-binary-expression': 'error',
'jsonc/no-binary-numeric-literals': 'error',
'jsonc/no-dupe-keys': 'error',
'jsonc/no-escape-sequence-in-identifier': 'error',
'jsonc/no-floating-decimal': 'error',
'jsonc/no-hexadecimal-numeric-literals': 'error',
'jsonc/no-infinity': 'error',
'jsonc/no-multi-str': 'error',
'jsonc/no-nan': 'error',
'jsonc/no-number-props': 'error',
'jsonc/no-numeric-separators': 'error',
'jsonc/no-octal': 'error',
'jsonc/no-octal-escape': 'error',
'jsonc/no-octal-numeric-literals': 'error',
'jsonc/no-parenthesized': 'error',
'jsonc/no-plus-sign': 'error',
'jsonc/no-regexp-literals': 'error',
'jsonc/no-sparse-arrays': 'error',
'jsonc/no-template-literals': 'error',
'jsonc/no-undefined-value': 'error',
'jsonc/no-unicode-codepoint-escapes': 'error',
'jsonc/no-useless-escape': 'error',
'jsonc/valid-json-number': 'error',
'jsonc/vue-custom-block/no-parsing-error': 'error',
},
},
{
files: ['**/package.json'],
rules: {
'jsonc/sort-array-values': [
'error',
{
order: { type: 'asc' },
pathPattern: '^files$',
},
],
},
},
{
files: ['**/[jt]sconfig.json', '**/[jt]sconfig.*.json'],
rules: {
'jsonc/sort-keys': [
'error',
{
order: ['extends', 'compilerOptions', 'references', 'files', 'include', 'exclude'],
pathPattern: '^$',
},
{
order: tsconfigCompilerOptionsOrder,
pathPattern: '^compilerOptions$',
},
],
},
},
{
files: ['package.json', '**/package.json'],
plugins: {
pnpm,
},
rules: {
'pnpm/json-enforce-catalog': [
'error',
{
autofix: true,
ignores: ['@types/vscode'],
},
],
'pnpm/json-prefer-workspace-settings': ['error', { autofix: true }],
'pnpm/json-valid-catalog': ['error', { autofix: true }],
},
},
{
files: ['**/*.{yml,yaml}'],
language: 'yml/yaml',
plugins: {
yml,
},
rules: {
'no-irregular-whitespace': 'off',
'no-unused-vars': 'off',
'spaced-comment': 'off',
'yml/no-empty-key': 'error',
'yml/no-empty-sequence-entry': 'error',
'yml/no-irregular-whitespace': 'error',
'yml/vue-custom-block/no-parsing-error': 'error',
},
},
{
files: ['pnpm-workspace.yaml'],
plugins: {
pnpm,
},
rules: {
'pnpm/yaml-enforce-settings': [
'error',
{
settings: {
shellEmulator: true,
trustPolicy: 'no-downgrade',
},
},
],
'pnpm/yaml-no-duplicate-catalog-item': 'error',
'pnpm/yaml-no-unused-catalog-item': 'error',
'yml/sort-keys': [
'error',
{
order: pnpmWorkspaceOrder,
pathPattern: '^$',
},
{
order: { type: 'asc' },
pathPattern: '.*',
},
],
},
},
{
files: ['**/*.toml'],
language: 'toml/toml',
plugins: {
toml,
},
rules: {
'no-irregular-whitespace': 'off',
'spaced-comment': 'off',
'toml/keys-order': 'error',
'toml/no-unreadable-number-separator': 'error',
'toml/precision-of-fractional-seconds': 'error',
'toml/precision-of-integer': 'error',
'toml/tables-order': 'error',
'toml/vue-custom-block/no-parsing-error': 'error',
},
},
{
files: ['**/*.md'],
language: 'markdown/gfm',
plugins: {
markdown,
'markdown-preferences': markdownPreferences,
md: mdPlugin,
},
rules: {
'markdown/fenced-code-language': 'off',
'markdown/heading-increment': 'error',
'markdown/no-duplicate-definitions': 'error',
'markdown/no-empty-definitions': 'error',
'markdown/no-empty-images': 'error',
'markdown/no-empty-links': 'error',
'markdown/no-invalid-label-refs': 'error',
'markdown/no-missing-atx-heading-space': 'error',
'markdown/no-missing-label-refs': 'off',
'markdown/no-missing-link-fragments': 'error',
'markdown/no-multiple-h1': 'error',
'markdown/no-reference-like-urls': 'error',
'markdown/no-reversed-media-syntax': 'error',
'markdown/no-space-in-emphasis': 'error',
'markdown/no-unused-definitions': 'error',
'markdown/require-alt-text': 'error',
'markdown/table-column-count': 'error',
'markdown-preferences/definitions-last': 'error',
'markdown-preferences/prefer-link-reference-definitions': [
'error',
{
minLinks: 1,
},
],
'markdown-preferences/sort-definitions': 'error',
'md/no-url-trailing-slash': 'error',
},
},
{
files: ['web/i18n/**/*.json'],
plugins: {
dify,
hyoban,
},
rules: {
'dify/consistent-placeholders': 'error',
'dify/no-extra-keys': 'error',
'hyoban/i18n-flat-key': 'error',
'jsonc/sort-keys': 'error',
},
},
])