diff --git a/web/eslint-rules/doc-redirects.js b/web/eslint-rules/doc-redirects.js deleted file mode 100644 index ece2e63289..0000000000 --- a/web/eslint-rules/doc-redirects.js +++ /dev/null @@ -1,70 +0,0 @@ -// GENERATE BY script -// DON NOT EDIT IT MANUALLY -// -// Generated from: https://raw.githubusercontent.com/langgenius/dify-docs/refs/heads/main/docs.json -// Generated at: 2026-01-12T08:33:31.591Z - -/** @type {Map} */ -export const docRedirects = new Map([ - ['guides/knowledge-base/retrieval-test-and-citation', 'use-dify/knowledge/test-retrieval'], - ['use-dify/knowledge/retrieval-test-and-citation', 'use-dify/knowledge/test-retrieval'], - ['use-dify/build/variables#conversation-variables', 'use-dify/getting-started/key-concepts#variables'], - ['use-dify/build/variables#会话变量', 'use-dify/getting-started/key-concepts#变量'], - ['use-dify/build/variables#会話変数', 'use-dify/getting-started/key-concepts#変数'], - ['guides/workflow/variables#conversation-variables', 'use-dify/getting-started/key-concepts#variables'], - ['guides/workflow/variables#会话变量', 'use-dify/getting-started/key-concepts#变量'], - ['guides/workflow/variables#会話変数', 'use-dify/getting-started/key-concepts#変数'], - ['guides/workflow/node/start', 'use-dify/getting-started/key-concepts#workflow'], - ['guides/workflow/node/user-input', 'use-dify/nodes/user-input'], - ['guides/workflow/node/trigger', 'use-dify/nodes/trigger/overview'], - ['guides/workflow/node/schedule-trigger', 'use-dify/nodes/trigger/schedule-trigger'], - ['guides/workflow/node/webhook-trigger', 'use-dify/nodes/trigger/webhook-trigger'], - ['guides/workflow/node/plugin-trigger', 'use-dify/nodes/trigger/plugin-trigger'], - ['guides/workflow/node/knowledge-retrieval', 'use-dify/nodes/knowledge-retrieval'], - ['guides/workflow/node/agent', 'use-dify/nodes/agent'], - ['guides/workflow/node/question-classifier', 'use-dify/nodes/question-classifier'], - ['guides/workflow/node/ifelse', 'use-dify/nodes/ifelse'], - ['guides/workflow/node/iteration', 'use-dify/nodes/iteration'], - ['guides/workflow/node/loop', 'use-dify/nodes/loop'], - ['guides/workflow/node/code', 'use-dify/nodes/code'], - ['guides/workflow/node/template', 'use-dify/nodes/template'], - ['guides/workflow/node/variable-aggregator', 'use-dify/nodes/variable-aggregator'], - ['guides/workflow/node/doc-extractor', 'use-dify/nodes/doc-extractor'], - ['guides/workflow/node/variable-assigner', 'use-dify/nodes/variable-assigner'], - ['guides/workflow/node/parameter-extractor', 'use-dify/nodes/parameter-extractor'], - ['guides/workflow/node/http-request', 'use-dify/nodes/http-request'], - ['guides/workflow/node/list-operator', 'use-dify/nodes/list-operator'], - ['guides/workflow/node/tools', 'use-dify/nodes/tools'], - ['guides/workflow/node/end', 'use-dify/nodes/output'], - ['guides/workflow/node/llm', 'use-dify/nodes/llm'], - ['getting-started/dify-for-education', 'use-dify/workspace/subscription-management#dify-for-education'], - ['/plugins/schema-definition/model', '/versions/legacy/en/plugins/schema-definition/model/model-designing-rules'], - ['/plugins/schema-definition', '/versions/legacy/en/plugins/schema-definition/manifest'], - ['/zh-hans', 'use-dify/getting-started/introduction'], - ['/introduction', 'use-dify/getting-started/introduction'], - ['introduction', 'use-dify/getting-started/introduction'], - ['/getting-started/readme/features-and-specifications', 'use-dify/getting-started/introduction'], - ['/getting-started/readme/model-providers', 'use-dify/getting-started/introduction'], - ['/getting-started/install-self-hosted', 'self-host/quick-start/docker-compose'], - ['/getting-started/install-self-hosted/docker-compose', 'self-host/quick-start/docker-compose'], - ['/getting-started/install-self-hosted/local-source-code', 'self-host/advanced-deployments/local-source-code'], - ['/getting-started/install-self-hosted/bt-panel', 'self-host/platform-guides/bt-panel'], - ['/getting-started/install-self-hosted/start-the-frontend-docker-container', 'self-host/advanced-deployments/start-the-frontend-docker-container'], - ['/getting-started/install-self-hosted/environments', 'self-host/configuration/environments'], - ['/getting-started/install-self-hosted/faqs', 'self-host/quick-start/faqs'], - ['/getting-started/cloud', 'use-dify/getting-started/introduction'], - ['/getting-started/dify-premium', 'self-host/platform-guides/dify-premium'], - ['guides/application-publishing/launch-your-webapp-quickly/readme', 'use-dify/publish/README'], - ['/plugins/quick-start', 'develop-plugin/getting-started/getting-started-dify-plugin'], - ['/plugins/quick-start/install-plugins', 'develop-plugin/getting-started/getting-started-dify-plugin'], - ['/plugins/quick-start/develop-plugins', 'develop-plugin/dev-guides-and-walkthroughs/cheatsheet'], - ['/plugins/quick-start/develop-plugins/initialize-development-tools', 'develop-plugin/getting-started/cli'], - ['/plugins/quick-start/develop-plugins/tool-plugin', 'develop-plugin/features-and-specs/plugin-types/tool'], - ['/plugins/quick-start/develop-plugins/model-plugin', 'develop-plugin/features-and-specs/plugin-types/model-schema'], - ['/plugins/quick-start/develop-plugins/model-plugin/create-model-providers', 'develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider'], - ['learn-more/extended-reading/dify-docs-mcp', 'use-dify/build/mcp'], - ['getting-started/cloud', 'use-dify/getting-started/introduction'], - ['getting-started/dify-premium', 'use-dify/getting-started/introduction'], - ['guides/model-configuration/load-balancing', 'use-dify/workspace/model-providers#configure-model-load-balancing'], - ['/guides/model-configuration/load-balancing', 'use-dify/workspace/model-providers#configure-model-load-balancing'], -]) diff --git a/web/eslint-rules/index.js b/web/eslint-rules/index.js index e879f8ddd4..66c2034625 100644 --- a/web/eslint-rules/index.js +++ b/web/eslint-rules/index.js @@ -1,5 +1,4 @@ import noAsAnyInT from './rules/no-as-any-in-t.js' -import noDeprecatedDocLink from './rules/no-deprecated-doc-link.js' import noExtraKeys from './rules/no-extra-keys.js' import noLegacyNamespacePrefix from './rules/no-legacy-namespace-prefix.js' import requireNsOption from './rules/require-ns-option.js' @@ -13,7 +12,6 @@ const plugin = { }, rules: { 'no-as-any-in-t': noAsAnyInT, - 'no-deprecated-doc-link': noDeprecatedDocLink, 'no-extra-keys': noExtraKeys, 'no-legacy-namespace-prefix': noLegacyNamespacePrefix, 'require-ns-option': requireNsOption, diff --git a/web/eslint-rules/rules/no-deprecated-doc-link.js b/web/eslint-rules/rules/no-deprecated-doc-link.js deleted file mode 100644 index 871aad9530..0000000000 --- a/web/eslint-rules/rules/no-deprecated-doc-link.js +++ /dev/null @@ -1,172 +0,0 @@ -import { docRedirects } from '../doc-redirects.js' - -/** @type {import('eslint').Rule.RuleModule} */ -export default { - meta: { - type: 'suggestion', - docs: { - description: 'Disallow deprecated documentation paths in useDocLink calls and auto-fix to new paths', - }, - fixable: 'code', - schema: [], - messages: { - deprecatedDocLink: - 'Deprecated documentation path detected. The path "{{oldPath}}" has been moved to "{{newPath}}".', - }, - }, - create(context) { - /** - * Check if the path needs redirect - * @param {string} docPath - Path without language prefix - */ - function checkRedirect(docPath) { - // Normalize path (remove leading slash if present) - const normalizedPath = docPath.startsWith('/') ? docPath.slice(1) : docPath - - if (docRedirects.has(normalizedPath)) { - return { - oldPath: normalizedPath, - newPath: docRedirects.get(normalizedPath), - } - } - - // Also check with leading slash - if (docRedirects.has(`/${normalizedPath}`)) { - return { - oldPath: normalizedPath, - newPath: docRedirects.get(`/${normalizedPath}`).replace(/^\//, ''), - } - } - - return null - } - - /** - * Check if node is a useDocLink call - * @param {import('estree').CallExpression} node - */ - function isUseDocLinkCall(node) { - // Check for direct useDocLink() call that returns a function - // The actual doc path is passed to the returned function - // e.g., const getLink = useDocLink(); getLink('path') - // or useDocLink()('path') - - // For the pattern: useDocLink()('path') - if ( - node.callee.type === 'CallExpression' - && node.callee.callee.type === 'Identifier' - && node.callee.callee.name === 'useDocLink' - ) { - return true - } - - return false - } - - /** - * Check if node is a call to a function returned by useDocLink - * This handles: const docLink = useDocLink(); docLink('path') - */ - function isDocLinkFunctionCall(node, scope) { - if (node.callee.type !== 'Identifier') - return false - - const calleeName = node.callee.name - - // Look for variable declaration that assigns useDocLink() - const variable = scope.variables.find(v => v.name === calleeName) - if (!variable || variable.defs.length === 0) - return false - - const def = variable.defs[0] - if (def.type !== 'Variable' || !def.node.init) - return false - - const init = def.node.init - - // Check if initialized with useDocLink() - if ( - init.type === 'CallExpression' - && init.callee.type === 'Identifier' - && init.callee.name === 'useDocLink' - ) { - return true - } - - return false - } - - /** - * Report a deprecated path and provide fix - */ - function reportDeprecatedPath(node, redirect, sourceCode) { - context.report({ - node, - messageId: 'deprecatedDocLink', - data: { - oldPath: redirect.oldPath, - newPath: redirect.newPath, - }, - fix(fixer) { - // Replace the string value, preserving the quote style - const raw = sourceCode.getText(node) - const quote = raw[0] - return fixer.replaceText(node, `${quote}${redirect.newPath}${quote}`) - }, - }) - } - - /** - * Check a string literal node for deprecated path - */ - function checkStringLiteral(node, sourceCode) { - if (node.type !== 'Literal' || typeof node.value !== 'string') - return - - const redirect = checkRedirect(node.value) - if (redirect) - reportDeprecatedPath(node, redirect, sourceCode) - } - - /** - * Check pathMap object for deprecated paths - * pathMap is like { en: 'path1', zh: 'path2' } - */ - function checkPathMapObject(node, sourceCode) { - if (node.type !== 'ObjectExpression') - return - - for (const prop of node.properties) { - if (prop.type !== 'Property') - continue - - // Check the value of each property - checkStringLiteral(prop.value, sourceCode) - } - } - - return { - CallExpression(node) { - const sourceCode = context.sourceCode || context.getSourceCode() - const scope = sourceCode.getScope?.(node) || context.getScope() - - // Check if this is useDocLink()('path') pattern - const isDirectCall = isUseDocLinkCall(node) - - // Check if this is docLink('path') where docLink = useDocLink() - const isIndirectCall = isDocLinkFunctionCall(node, scope) - - if (!isDirectCall && !isIndirectCall) - return - - // Check first argument (the doc path) - if (node.arguments.length >= 1) - checkStringLiteral(node.arguments[0], sourceCode) - - // Check second argument (pathMap object) - if (node.arguments.length >= 2) - checkPathMapObject(node.arguments[1], sourceCode) - }, - } - }, -} diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index 81f243d055..e671ec49fe 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -178,7 +178,6 @@ export default antfu( rules: { // 'dify-i18n/no-as-any-in-t': ['error', { mode: 'all' }], 'dify-i18n/no-as-any-in-t': 'error', - 'dify-i18n/no-deprecated-doc-link': 'error', // 'dify-i18n/no-legacy-namespace-prefix': 'error', // 'dify-i18n/require-ns-option': 'error', }, diff --git a/web/scripts/gen-doc-paths.ts b/web/scripts/gen-doc-paths.ts index 8cf28a38ec..aa6617db37 100644 --- a/web/scripts/gen-doc-paths.ts +++ b/web/scripts/gen-doc-paths.ts @@ -13,7 +13,6 @@ import { fileURLToPath } from 'node:url' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const DOCS_JSON_URL = 'https://raw.githubusercontent.com/langgenius/dify-docs/refs/heads/main/docs.json' const OUTPUT_PATH = path.resolve(__dirname, '../types/doc-paths.ts') -const REDIRECTS_PATH = path.resolve(__dirname, '../eslint-rules/doc-redirects.js') type NavItem = string | NavObject | NavItem[] @@ -474,13 +473,6 @@ async function main(): Promise { await writeFile(OUTPUT_PATH, tsContent, 'utf-8') // eslint-disable-next-line no-console console.log(`Generated TypeScript types at: ${OUTPUT_PATH}`) - - // Generate redirects module for ESLint rule - const redirects = docsJson.redirects || [] - const redirectsContent = generateRedirectsModule(redirects) - await writeFile(REDIRECTS_PATH, redirectsContent, 'utf-8') - // eslint-disable-next-line no-console - console.log(`Generated redirects module at: ${REDIRECTS_PATH} (${redirects.length} redirects)`) } main().catch((err: Error) => {