chore: workspace lint (#35331)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Stephen Zhou 2026-04-17 00:47:53 +08:00 committed by GitHub
parent 4289cb2634
commit 40e040ca1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 2089 additions and 1692 deletions

View File

@ -120,7 +120,6 @@ jobs:
- name: ESLint autofix
if: github.event_name != 'merge_group' && steps.web-changes.outputs.any_changed == 'true'
run: |
cd web
vp exec eslint --concurrency=2 --prune-suppressions --quiet || true
- if: github.event_name != 'merge_group'

View File

@ -97,14 +97,14 @@ jobs:
id: eslint-cache-restore
uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: web/.eslintcache
key: ${{ runner.os }}-web-eslint-${{ hashFiles('web/package.json', 'pnpm-lock.yaml', 'web/eslint.config.mjs', 'web/eslint.constants.mjs', 'web/plugins/eslint/**') }}-${{ github.sha }}
path: .eslintcache
key: ${{ runner.os }}-eslint-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'web/eslint.config.mjs', 'web/eslint.constants.mjs', 'web/plugins/eslint/**') }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-web-eslint-${{ hashFiles('web/package.json', 'pnpm-lock.yaml', 'web/eslint.config.mjs', 'web/eslint.constants.mjs', 'web/plugins/eslint/**') }}-
${{ runner.os }}-eslint-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'web/eslint.config.mjs', 'web/eslint.constants.mjs', 'web/plugins/eslint/**') }}-
- name: Web style check
if: steps.changed-files.outputs.any_changed == 'true'
working-directory: ./web
working-directory: .
run: vp run lint:ci
- name: Web tsslint
@ -126,7 +126,7 @@ jobs:
if: steps.changed-files.outputs.any_changed == 'true' && success() && steps.eslint-cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: web/.eslintcache
path: .eslintcache
key: ${{ steps.eslint-cache-restore.outputs.cache-primary-key }}
superlinter:

3
.gitignore vendored
View File

@ -203,6 +203,7 @@ sdks/python-client/dify_client.egg-info
.vscode/*
!.vscode/launch.json.template
!.vscode/settings.example.json
!.vscode/README.md
api/.vscode
# vscode Code History Extension
@ -242,3 +243,5 @@ scripts/stress-test/reports/
# Code Agent Folder
.qoder/*
.eslintcache

View File

@ -56,16 +56,9 @@ if $api_modified; then
fi
fi
if $web_modified; then
if $skip_web_checks; then
echo "Git operation in progress, skipping web checks"
exit 0
fi
echo "Running ESLint on web module"
cd ./web || exit 1
vp staged
cd ../
if $skip_web_checks; then
echo "Git operation in progress, skipping web checks"
exit 0
fi
vp staged

View File

@ -1,12 +1,16 @@
{
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,
"cucumber.features": [
"e2e/features/**/*.feature",
],
"cucumber.glue": [
"e2e/features/**/*.ts",
],
"tailwindCSS.experimental.configFile": "web/app/styles/globals.css",
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
// Silent the stylistic rules in your IDE, but still auto fix them

View File

@ -171,10 +171,10 @@ open cucumber-report/report.html
### Workflow
1. Create a `.feature` file under `features/<capability>/`
2. Add step definitions under `features/step-definitions/<capability>/`
3. Reuse existing steps from `common/` and other definition files before writing new ones
4. Run with `pnpm -C e2e e2e -- --tags @your-tag` to verify
5. Run `pnpm -C e2e check` before committing
1. Add step definitions under `features/step-definitions/<capability>/`
1. Reuse existing steps from `common/` and other definition files before writing new ones
1. Run with `pnpm -C e2e e2e -- --tags @your-tag` to verify
1. Run `pnpm -C e2e check` before committing
### Feature file conventions
@ -202,9 +202,9 @@ Keep scenarios short and declarative. Each step should describe **what** the use
### Step definition conventions
```typescript
import { When, Then } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
When('I open the datasets page', async function (this: DifyWorld) {
await this.getPage().goto('/datasets')

View File

@ -1,3 +1,5 @@
# E2E
Canonical documentation for this package lives in [AGENTS.md](./AGENTS.md).
Canonical documentation for this package lives in [AGENTS.md].
[AGENTS.md]: ./AGENTS.md

View File

@ -1,6 +1,6 @@
import type { DifyWorld } from '../../support/world'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
When('I start creating a blank app', async function (this: DifyWorld) {
const page = this.getPage()

View File

@ -1,6 +1,6 @@
import type { DifyWorld } from '../../support/world'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
When('I open the account menu', async function (this: DifyWorld) {
const page = this.getPage()

View File

@ -1,5 +1,5 @@
import { Given } from '@cucumber/cucumber'
import type { DifyWorld } from '../../support/world'
import { Given } from '@cucumber/cucumber'
Given('I am signed in as the default E2E admin', async function (this: DifyWorld) {
const session = await this.getAuthSession()

View File

@ -1,6 +1,6 @@
import type { DifyWorld } from '../../support/world'
import { Then, When } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
When('I open the apps console', async function (this: DifyWorld) {
await this.getPage().goto('/apps')

View File

@ -1,6 +1,6 @@
import type { DifyWorld } from '../../support/world'
import { Given } from '@cucumber/cucumber'
import { expect } from '@playwright/test'
import type { DifyWorld } from '../../support/world'
Given(
'the last authentication bootstrap came from a fresh install',

View File

@ -1,11 +1,12 @@
import { After, AfterAll, Before, BeforeAll, Status, setDefaultTimeout } from '@cucumber/cucumber'
import { chromium, type Browser } from '@playwright/test'
import type { Browser } from '@playwright/test'
import type { DifyWorld } from './world'
import { mkdir, writeFile } from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { After, AfterAll, Before, BeforeAll, setDefaultTimeout, Status } from '@cucumber/cucumber'
import { chromium } from '@playwright/test'
import { AUTH_BOOTSTRAP_TIMEOUT_MS, ensureAuthenticatedState } from '../../fixtures/auth'
import { baseURL, cucumberHeadless, cucumberSlowMo } from '../../test-env'
import type { DifyWorld } from './world'
const e2eRoot = fileURLToPath(new URL('../..', import.meta.url))
const artifactsDir = path.join(e2eRoot, 'cucumber-report', 'artifacts')
@ -15,7 +16,7 @@ let browser: Browser | undefined
setDefaultTimeout(60_000)
const sanitizeForPath = (value: string) =>
value.replaceAll(/[^a-zA-Z0-9_-]+/g, '-').replaceAll(/^-+|-+$/g, '')
value.replaceAll(/[^\w-]+/g, '-').replaceAll(/^-+|-+$/g, '')
const writeArtifact = async (
scenarioName: string,
@ -44,16 +45,18 @@ BeforeAll({ timeout: AUTH_BOOTSTRAP_TIMEOUT_MS }, async () => {
})
Before(async function (this: DifyWorld, { pickle }) {
if (!browser) throw new Error('Shared Playwright browser is not available.')
if (!browser)
throw new Error('Shared Playwright browser is not available.')
const isUnauthenticatedScenario = pickle.tags.some((tag) => tag.name === '@unauthenticated')
const isUnauthenticatedScenario = pickle.tags.some(tag => tag.name === '@unauthenticated')
if (isUnauthenticatedScenario) await this.startUnauthenticatedSession(browser)
if (isUnauthenticatedScenario)
await this.startUnauthenticatedSession(browser)
else await this.startAuthenticatedSession(browser)
this.scenarioStartedAt = Date.now()
const tags = pickle.tags.map((tag) => tag.name).join(' ')
const tags = pickle.tags.map(tag => tag.name).join(' ')
console.log(`[e2e] start ${pickle.name}${tags ? ` ${tags}` : ''}`)
})

View File

@ -1,9 +1,11 @@
import { type IWorldOptions, World, setWorldConstructor } from '@cucumber/cucumber'
import type { IWorldOptions } from '@cucumber/cucumber'
import type { Browser, BrowserContext, ConsoleMessage, Page } from '@playwright/test'
import type { AuthSessionMetadata } from '../../fixtures/auth'
import { setWorldConstructor, World } from '@cucumber/cucumber'
import {
authStatePath,
readAuthSessionMetadata,
type AuthSessionMetadata,
} from '../../fixtures/auth'
import { baseURL, defaultLocale } from '../../test-env'
@ -37,7 +39,8 @@ export class DifyWorld extends World {
this.page.setDefaultTimeout(30_000)
this.page.on('console', (message: ConsoleMessage) => {
if (message.type() === 'error') this.consoleErrors.push(message.text())
if (message.type() === 'error')
this.consoleErrors.push(message.text())
})
this.page.on('pageerror', (error) => {
this.pageErrors.push(error.message)
@ -53,7 +56,8 @@ export class DifyWorld extends World {
}
getPage() {
if (!this.page) throw new Error('Playwright page has not been initialized for this scenario.')
if (!this.page)
throw new Error('Playwright page has not been initialized for this scenario.')
return this.page
}

View File

@ -1,8 +1,8 @@
import type { Browser, Page } from '@playwright/test'
import { expect } from '@playwright/test'
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { expect } from '@playwright/test'
import { defaultBaseURL, defaultLocale } from '../test-env'
export type AuthSessionMetadata = {
@ -60,7 +60,8 @@ const waitForPageState = async (page: Page, deadline: number): Promise<AuthPageS
.waitFor({ state: 'visible', timeout: getRemainingTimeout(deadline) })
.then(() => 'init'),
])
} catch {
}
catch {
throw new Error(`Unable to determine auth page state for ${page.url()}`)
}
}
@ -73,7 +74,8 @@ const completeInitPasswordIfNeeded = async (page: Page, deadline: number) => {
.then(() => true)
.catch(() => false)
if (!needsInitPassword) return false
if (!needsInitPassword)
return false
await initPasswordField.fill(initPassword)
await page.getByRole('button', { name: 'Validate' }).click()
@ -143,7 +145,8 @@ export const ensureAuthenticatedState = async (browser: Browser, configuredBaseU
pageState = await waitForPageState(page, deadline)
}
if (pageState === 'install') await completeInstall(page, baseURL, deadline)
if (pageState === 'install')
await completeInstall(page, baseURL, deadline)
else await completeLogin(page, baseURL, deadline)
await expect(page.getByRole('button', { name: 'Create from Blank' })).toBeVisible({
@ -160,7 +163,8 @@ export const ensureAuthenticatedState = async (browser: Browser, configuredBaseU
}
await writeFile(authMetadataPath, `${JSON.stringify(metadata, null, 2)}\n`, 'utf8')
} finally {
}
finally {
await context.close()
}
}

View File

@ -1,7 +1,7 @@
{
"name": "dify-e2e",
"private": true,
"type": "module",
"private": true,
"scripts": {
"check": "vp check --fix",
"e2e": "tsx ./scripts/run-cucumber.ts",
@ -15,8 +15,8 @@
"type-check": "tsc"
},
"devDependencies": {
"@dify/tsconfig": "workspace:*",
"@cucumber/cucumber": "catalog:",
"@dify/tsconfig": "workspace:*",
"@playwright/test": "catalog:",
"@types/node": "catalog:",
"tsx": "catalog:",

View File

@ -1,4 +1,5 @@
import { spawn, type ChildProcess } from 'node:child_process'
import type { ChildProcess } from 'node:child_process'
import { spawn } from 'node:child_process'
import { createHash } from 'node:crypto'
import { access, copyFile, readFile, writeFile } from 'node:fs/promises'
import net from 'node:net'
@ -48,7 +49,8 @@ const formatCommand = (command: string, args: string[]) => [command, ...args].jo
export const isMainModule = (metaUrl: string) => {
const entrypoint = process.argv[1]
if (!entrypoint) return false
if (!entrypoint)
return false
return pathToFileURL(entrypoint).href === metaUrl
}
@ -107,7 +109,8 @@ export const runCommandOrThrow = async (options: RunCommandOptions) => {
const forwardSignalsToChild = (childProcess: ChildProcess) => {
const handleSignal = (signal: NodeJS.Signals) => {
if (childProcess.exitCode === null) childProcess.kill(signal)
if (childProcess.exitCode === null)
childProcess.kill(signal)
}
const onSigint = () => handleSignal('SIGINT')
@ -152,7 +155,8 @@ export const runForegroundProcess = async ({
export const ensureFileExists = async (filePath: string, exampleFilePath: string) => {
try {
await access(filePath)
} catch {
}
catch {
await copyFile(exampleFilePath, filePath)
}
}
@ -162,9 +166,10 @@ export const ensureLineInFile = async (filePath: string, line: string) => {
const lines = fileContent.split(/\r?\n/)
const assignmentPrefix = line.includes('=') ? `${line.slice(0, line.indexOf('='))}=` : null
if (lines.includes(line)) return
if (lines.includes(line))
return
if (assignmentPrefix && lines.some((existingLine) => existingLine.startsWith(assignmentPrefix)))
if (assignmentPrefix && lines.some(existingLine => existingLine.startsWith(assignmentPrefix)))
return
const normalizedContent = fileContent.endsWith('\n') ? fileContent : `${fileContent}\n`
@ -187,16 +192,16 @@ export const readSimpleDotenv = async (filePath: string) => {
const fileContent = await readFile(filePath, 'utf8')
const entries = fileContent
.split(/\r?\n/)
.map((line) => line.trim())
.filter((line) => line && !line.startsWith('#'))
.map(line => line.trim())
.filter(line => line && !line.startsWith('#'))
.map<[string, string]>((line) => {
const separatorIndex = line.indexOf('=')
const key = separatorIndex === -1 ? line : line.slice(0, separatorIndex).trim()
const rawValue = separatorIndex === -1 ? '' : line.slice(separatorIndex + 1).trim()
if (
(rawValue.startsWith('"') && rawValue.endsWith('"')) ||
(rawValue.startsWith("'") && rawValue.endsWith("'"))
(rawValue.startsWith('"') && rawValue.endsWith('"'))
|| (rawValue.startsWith('\'') && rawValue.endsWith('\''))
) {
return [key, rawValue.slice(1, -1)]
}
@ -221,7 +226,8 @@ export const waitForCondition = async ({
const deadline = Date.now() + timeoutMs
while (Date.now() < deadline) {
if (await check()) return
if (await check())
return
await sleep(intervalMs)
}

View File

@ -1,7 +1,7 @@
import { mkdir, rm } from 'node:fs/promises'
import path from 'node:path'
import { startLoggedProcess, stopManagedProcess, waitForUrl } from '../support/process'
import { startWebServer, stopWebServer } from '../support/web-server'
import { waitForUrl, startLoggedProcess, stopManagedProcess } from '../support/process'
import { apiURL, baseURL, reuseExistingWebServer } from '../test-env'
import { e2eDir, isMainModule, runCommand } from './common'
import { resetState, startMiddleware, stopMiddleware } from './setup'
@ -40,16 +40,18 @@ const parseArgs = (argv: string[]): RunOptions => {
}
const hasCustomTags = (forwardArgs: string[]) =>
forwardArgs.some((arg) => arg === '--tags' || arg.startsWith('--tags='))
forwardArgs.some(arg => arg === '--tags' || arg.startsWith('--tags='))
const main = async () => {
const { forwardArgs, full, headed } = parseArgs(process.argv.slice(2))
const startMiddlewareForRun = full
const resetStateForRun = full
if (resetStateForRun) await resetState()
if (resetStateForRun)
await resetState()
if (startMiddlewareForRun) await startMiddleware()
if (startMiddlewareForRun)
await startMiddleware()
const cucumberReportDir = path.join(e2eDir, 'cucumber-report')
const logDir = path.join(e2eDir, '.logs')
@ -75,7 +77,8 @@ const main = async () => {
if (startMiddlewareForRun) {
try {
await stopMiddleware()
} catch {
}
catch {
// Cleanup should continue even if middleware shutdown fails.
}
}
@ -97,7 +100,8 @@ const main = async () => {
try {
try {
await waitForUrl(`${apiURL}/health`, 180_000, 1_000)
} catch {
}
catch {
throw new Error(`API did not become ready at ${apiURL}/health.`)
}
@ -133,7 +137,8 @@ const main = async () => {
})
process.exitCode = result.exitCode
} finally {
}
finally {
process.off('SIGINT', onTerminate)
process.off('SIGTERM', onTerminate)
await cleanup()

View File

@ -5,8 +5,8 @@ import {
apiDir,
apiEnvExampleFile,
dockerDir,
e2eWebEnvOverrides,
e2eDir,
e2eWebEnvOverrides,
ensureFileExists,
ensureLineInFile,
getWebEnvLocalHash,
@ -79,7 +79,8 @@ const getContainerHealth = async (containerId: string) => {
stdio: 'pipe',
})
if (result.exitCode !== 0) return ''
if (result.exitCode !== 0)
return ''
return result.stdout.trim()
}
@ -105,7 +106,8 @@ const waitForDependency = async ({
try {
await wait()
} catch (error) {
}
catch (error) {
await printComposeLogs(services)
throw error
}
@ -134,7 +136,7 @@ export const ensureWebBuild = async () => {
.then(() => true)
.catch(() => false),
readFile(webBuildEnvStampPath, 'utf8')
.then((value) => value.trim())
.then(value => value.trim())
.catch(() => ''),
])
@ -142,7 +144,8 @@ export const ensureWebBuild = async () => {
console.log('Reusing existing web build artifact.')
return
}
} catch {
}
catch {
// Fall through to rebuild when the existing build cannot be verified.
}
@ -211,7 +214,8 @@ export const resetState = async () => {
console.log('Stopping middleware services...')
try {
await stopMiddleware()
} catch {
}
catch {
// Reset should continue even if middleware is already stopped.
}
@ -225,7 +229,7 @@ export const resetState = async () => {
console.log('Removing E2E local state...')
await Promise.all(
e2eStatePaths.map((targetPath) => rm(targetPath, { force: true, recursive: true })),
e2eStatePaths.map(targetPath => rm(targetPath, { force: true, recursive: true })),
)
console.log('E2E state reset complete.')

View File

@ -1,6 +1,7 @@
import type { ChildProcess } from 'node:child_process'
import type { WriteStream } from 'node:fs'
import { spawn } from 'node:child_process'
import { createWriteStream, type WriteStream } from 'node:fs'
import { createWriteStream } from 'node:fs'
import { mkdir } from 'node:fs/promises'
import net from 'node:net'
import { dirname } from 'node:path'
@ -63,11 +64,14 @@ export const waitForUrl = async (
const response = await fetch(url, {
signal: controller.signal,
})
if (response.ok) return
} finally {
if (response.ok)
return
}
finally {
clearTimeout(timeout)
}
} catch {
}
catch {
// Keep polling until timeout.
}
@ -138,7 +142,8 @@ const waitForProcessExit = (childProcess: ChildProcess, timeoutMs: number) =>
const signalManagedProcess = (childProcess: ChildProcess, signal: NodeJS.Signals) => {
const { pid } = childProcess
if (!pid) return
if (!pid)
return
try {
if (process.platform !== 'win32') {
@ -147,13 +152,15 @@ const signalManagedProcess = (childProcess: ChildProcess, signal: NodeJS.Signals
}
childProcess.kill(signal)
} catch {
}
catch {
// Best-effort shutdown. Cleanup continues even when the process is already gone.
}
}
export const stopManagedProcess = async (managedProcess?: ManagedProcess) => {
if (!managedProcess) return
if (!managedProcess)
return
const { childProcess, logStream } = managedProcess

View File

@ -34,7 +34,8 @@ export const startWebServer = async ({
}: WebServerStartOptions) => {
const { host, port } = getUrlHostAndPort(baseURL)
if (reuseExistingServer && (await isPortReachable(host, port))) return
if (reuseExistingServer && (await isPortReachable(host, port)))
return
activeProcess = await startLoggedProcess({
command,
@ -49,7 +50,8 @@ export const startWebServer = async ({
startupError = error
})
activeProcess.childProcess.once('exit', (code, signal) => {
if (startupError) return
if (startupError)
return
startupError = new Error(
`Web server exited before readiness (code: ${code ?? 'unknown'}, signal: ${signal ?? 'none'}).`,
@ -67,7 +69,8 @@ export const startWebServer = async ({
try {
await waitForUrl(baseURL, 1_000, 250, 1_000)
return
} catch {
}
catch {
// Continue polling until timeout or child exit.
}
}

View File

@ -2,8 +2,8 @@
"extends": "@dify/tsconfig/node.json",
"compilerOptions": {
"lib": ["ES2023", "DOM"],
"allowJs": false,
"types": ["node", "@playwright/test", "@cucumber/cucumber"],
"allowJs": false,
"verbatimModuleSyntax": true
},
"include": ["./**/*.ts"],

View File

@ -1,15 +1,5 @@
import { defineConfig } from 'vite-plus'
export default defineConfig({
lint: {
options: {
typeAware: true,
typeCheck: true,
denyWarnings: true,
},
},
fmt: {
singleQuote: true,
semi: false,
},
})

File diff suppressed because it is too large Load Diff

65
eslint.config.mjs Normal file
View File

@ -0,0 +1,65 @@
// @ts-check
import antfu, { GLOB_MARKDOWN } from '@antfu/eslint-config'
import md from 'eslint-markdown'
import markdownPreferences from 'eslint-plugin-markdown-preferences'
export default antfu(
{
ignores: original => [
'**',
'!packages/**',
'!web/**',
'!e2e/**',
'!eslint.config.mjs',
'!package.json',
'!vite.config.ts',
...original,
],
typescript: {
overrides: {
'ts/consistent-type-definitions': ['error', 'type'],
'ts/no-explicit-any': 'error',
'ts/no-redeclare': 'off',
},
erasableOnly: true,
},
test: {
overrides: {
'test/prefer-lowercase-title': 'off',
},
},
stylistic: {
overrides: {
'antfu/top-level-function': 'off',
},
},
e18e: false,
pnpm: false,
},
markdownPreferences.configs.standard,
{
files: [GLOB_MARKDOWN],
plugins: { md },
rules: {
'md/no-url-trailing-slash': 'error',
'markdown-preferences/prefer-link-reference-definitions': [
'error',
{
minLinks: 1,
},
],
'markdown-preferences/ordered-list-marker-sequence': [
'error',
{ increment: 'never' },
],
'markdown-preferences/definitions-last': 'error',
'markdown-preferences/sort-definitions': 'error',
},
},
{
rules: {
'node/prefer-global/process': 'off',
},
},
)

View File

@ -1,16 +1,26 @@
{
"name": "dify",
"type": "module",
"private": true,
"scripts": {
"prepare": "vp config",
"type-check": "vp run -r type-check"
},
"devDependencies": {
"vite": "catalog:",
"vite-plus": "catalog:"
},
"packageManager": "pnpm@10.33.0",
"engines": {
"node": "^22.22.1"
},
"packageManager": "pnpm@10.33.0"
"scripts": {
"prepare": "vp config",
"type-check": "vp run -r type-check",
"lint": "eslint --cache --concurrency=auto",
"lint:ci": "eslint --cache --cache-strategy content --concurrency 2",
"lint:fix": "vp run lint --fix",
"lint:quiet": "vp run lint --quiet"
},
"devDependencies": {
"@antfu/eslint-config": "catalog:",
"eslint": "catalog:",
"eslint-markdown": "catalog:",
"eslint-plugin-markdown-preferences": "catalog:",
"eslint-plugin-no-barrel-files": "catalog:",
"vite": "catalog:",
"vite-plus": "catalog:"
}
}

View File

@ -6,18 +6,18 @@ This package provides shared design tokens (colors, shadows, typography), the `c
The Figma design system uses `--radius/*` tokens whose scale is **offset by one step** from Tailwind CSS v4 defaults. When translating Figma specs to code, always use this mapping — never use `radius-*` as a CSS class, and never extend `borderRadius` in the preset.
| Figma Token | Value | Tailwind Class |
|---|---|---|
| `--radius/2xs` | 2px | `rounded-xs` |
| `--radius/xs` | 4px | `rounded-sm` |
| `--radius/sm` | 6px | `rounded-md` |
| `--radius/md` | 8px | `rounded-lg` |
| `--radius/lg` | 10px | `rounded-[10px]` |
| `--radius/xl` | 12px | `rounded-xl` |
| `--radius/2xl` | 16px | `rounded-2xl` |
| `--radius/3xl` | 20px | `rounded-[20px]` |
| `--radius/6xl` | 28px | `rounded-[28px]` |
| `--radius/full` | 999px | `rounded-full` |
| Figma Token | Value | Tailwind Class |
| --------------- | ----- | ---------------- |
| `--radius/2xs` | 2px | `rounded-xs` |
| `--radius/xs` | 4px | `rounded-sm` |
| `--radius/sm` | 6px | `rounded-md` |
| `--radius/md` | 8px | `rounded-lg` |
| `--radius/lg` | 10px | `rounded-[10px]` |
| `--radius/xl` | 12px | `rounded-xl` |
| `--radius/2xl` | 16px | `rounded-2xl` |
| `--radius/3xl` | 20px | `rounded-[20px]` |
| `--radius/6xl` | 28px | `rounded-[28px]` |
| `--radius/full` | 999px | `rounded-full` |
### Rules

View File

@ -1,19 +1,22 @@
{
"name": "@langgenius/dify-ui",
"type": "module",
"version": "0.0.1",
"private": true,
"type": "module",
"exports": {
"./styles.css": "./src/styles/styles.css",
"./tailwind-preset": {
"import": "./src/tailwind-preset.ts",
"types": "./src/tailwind-preset.ts"
"types": "./src/tailwind-preset.ts",
"import": "./src/tailwind-preset.ts"
},
"./cn": {
"import": "./src/cn.ts",
"types": "./src/cn.ts"
"types": "./src/cn.ts",
"import": "./src/cn.ts"
}
},
"scripts": {
"type-check": "tsc"
},
"dependencies": {
"clsx": "catalog:",
"tailwind-merge": "catalog:"
@ -22,8 +25,5 @@
"@dify/tsconfig": "workspace:*",
"tailwindcss": "catalog:",
"typescript": "catalog:"
},
"scripts": {
"type-check": "tsc"
}
}

View File

@ -1,12 +1,12 @@
{
"extends": "@dify/tsconfig/base.json",
"compilerOptions": {
"noEmit": false,
"rootDir": "src",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"noEmit": false,
"outDir": "dist",
"rootDir": "src",
"sourceMap": true,
"isolatedModules": true,
"verbatimModuleSyntax": true
},

View File

@ -1,4 +1,4 @@
export interface IconifyJSON {
export type IconifyJSON = {
prefix: string
icons: Record<string, IconifyIcon>
aliases?: Record<string, IconifyAlias>
@ -7,7 +7,7 @@ export interface IconifyJSON {
lastModified?: number
}
export interface IconifyIcon {
export type IconifyIcon = {
body: string
left?: number
top?: number
@ -18,11 +18,11 @@ export interface IconifyIcon {
vFlip?: boolean
}
export interface IconifyAlias extends Omit<IconifyIcon, 'body'> {
export type IconifyAlias = {
parent: string
}
} & Omit<IconifyIcon, 'body'>
export interface IconifyInfo {
export type IconifyInfo = {
prefix: string
name: string
total: number
@ -40,11 +40,11 @@ export interface IconifyInfo {
palette?: boolean
}
export interface IconifyMetaData {
export type IconifyMetaData = {
[key: string]: unknown
}
export interface IconifyChars {
export type IconifyChars = {
[key: string]: string
}
@ -52,4 +52,3 @@ export declare const icons: IconifyJSON
export declare const info: IconifyInfo
export declare const metadata: IconifyMetaData
export declare const chars: IconifyChars

View File

@ -1,9 +1,8 @@
'use strict'
const chars = require('./chars.json')
const icons = require('./icons.json')
const info = require('./info.json')
const metadata = require('./metadata.json')
const chars = require('./chars.json')
module.exports = { icons, info, metadata, chars }

View File

@ -1,7 +1,6 @@
import chars from './chars.json' with { type: 'json' }
import icons from './icons.json' with { type: 'json' }
import info from './info.json' with { type: 'json' }
import metadata from './metadata.json' with { type: 'json' }
import chars from './chars.json' with { type: 'json' }
export { icons, info, metadata, chars }
export { chars, icons, info, metadata }

View File

@ -1,4 +1,4 @@
export interface IconifyJSON {
export type IconifyJSON = {
prefix: string
icons: Record<string, IconifyIcon>
aliases?: Record<string, IconifyAlias>
@ -7,7 +7,7 @@ export interface IconifyJSON {
lastModified?: number
}
export interface IconifyIcon {
export type IconifyIcon = {
body: string
left?: number
top?: number
@ -18,11 +18,11 @@ export interface IconifyIcon {
vFlip?: boolean
}
export interface IconifyAlias extends Omit<IconifyIcon, 'body'> {
export type IconifyAlias = {
parent: string
}
} & Omit<IconifyIcon, 'body'>
export interface IconifyInfo {
export type IconifyInfo = {
prefix: string
name: string
total: number
@ -40,11 +40,11 @@ export interface IconifyInfo {
palette?: boolean
}
export interface IconifyMetaData {
export type IconifyMetaData = {
[key: string]: unknown
}
export interface IconifyChars {
export type IconifyChars = {
[key: string]: string
}
@ -52,4 +52,3 @@ export declare const icons: IconifyJSON
export declare const info: IconifyInfo
export declare const metadata: IconifyMetaData
export declare const chars: IconifyChars

View File

@ -1,9 +1,8 @@
'use strict'
const chars = require('./chars.json')
const icons = require('./icons.json')
const info = require('./info.json')
const metadata = require('./metadata.json')
const chars = require('./chars.json')
module.exports = { icons, info, metadata, chars }

View File

@ -1,7 +1,6 @@
import chars from './chars.json' with { type: 'json' }
import icons from './icons.json' with { type: 'json' }
import info from './info.json' with { type: 'json' }
import metadata from './metadata.json' with { type: 'json' }
import chars from './chars.json' with { type: 'json' }
export { icons, info, metadata, chars }
export { chars, icons, info, metadata }

View File

@ -1,12 +1,12 @@
{
"name": "@dify/iconify-collections",
"private": true,
"version": "0.0.0-private",
"private": true,
"exports": {
"./custom-public": {
"types": "./custom-public/index.d.ts",
"require": "./custom-public/index.js",
"import": "./custom-public/index.mjs"
"import": "./custom-public/index.mjs",
"require": "./custom-public/index.js"
},
"./custom-public/icons.json": "./custom-public/icons.json",
"./custom-public/info.json": "./custom-public/info.json",
@ -14,8 +14,8 @@
"./custom-public/chars.json": "./custom-public/chars.json",
"./custom-vender": {
"types": "./custom-vender/index.d.ts",
"require": "./custom-vender/index.js",
"import": "./custom-vender/index.mjs"
"import": "./custom-vender/index.mjs",
"require": "./custom-vender/index.js"
},
"./custom-vender/icons.json": "./custom-vender/icons.json",
"./custom-vender/info.json": "./custom-vender/info.json",

View File

@ -1,8 +1,8 @@
{
"name": "migrate-no-unchecked-indexed-access",
"private": true,
"version": "0.0.0-private",
"type": "module",
"version": "0.0.0-private",
"private": true,
"bin": {
"migrate-no-unchecked-indexed-access": "./bin/migrate-no-unchecked-indexed-access.js"
},

265
pnpm-lock.yaml generated
View File

@ -574,6 +574,21 @@ importers:
.:
devDependencies:
'@antfu/eslint-config':
specifier: 'catalog:'
version: 8.2.0(@eslint-react/eslint-plugin@3.0.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@next/eslint-plugin-next@16.2.3)(@typescript-eslint/rule-tester@8.57.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2))(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vue/compiler-sfc@3.5.31)(eslint-plugin-react-refresh@0.5.2(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.20.0))(typescript@6.0.2)(vitest@4.1.4)
eslint:
specifier: 'catalog:'
version: 10.2.0(jiti@2.6.1)
eslint-markdown:
specifier: 'catalog:'
version: 0.6.1(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-markdown-preferences:
specifier: 'catalog:'
version: 0.41.1(@eslint/markdown@8.0.1)(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-no-barrel-files:
specifier: 'catalog:'
version: 1.3.1(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)
vite:
specifier: npm:@voidzero-dev/vite-plus-core@0.1.18
version: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)'
@ -4532,15 +4547,38 @@ packages:
'@vitest/expect@3.2.4':
resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==}
'@vitest/expect@4.1.4':
resolution: {integrity: sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==}
'@vitest/mocker@4.1.4':
resolution: {integrity: sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==}
peerDependencies:
msw: ^2.4.9
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
'@vitest/pretty-format@3.2.4':
resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==}
'@vitest/pretty-format@4.1.4':
resolution: {integrity: sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==}
'@vitest/runner@4.1.4':
resolution: {integrity: sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==}
'@vitest/snapshot@4.1.4':
resolution: {integrity: sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==}
'@vitest/spy@3.2.4':
resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==}
'@vitest/spy@4.1.4':
resolution: {integrity: sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==}
'@vitest/utils@3.2.4':
resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==}
@ -5006,6 +5044,10 @@ packages:
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
engines: {node: '>=18'}
chai@6.2.2:
resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
engines: {node: '>=18'}
chalk@4.1.1:
resolution: {integrity: sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==}
engines: {node: '>=10'}
@ -5970,6 +6012,10 @@ packages:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
expect-type@1.3.0:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
exsolve@1.0.8:
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
@ -7810,6 +7856,9 @@ packages:
resolution: {integrity: sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==}
engines: {node: '>=20'}
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
@ -7882,6 +7931,9 @@ packages:
engines: {node: '>=20.16.0'}
hasBin: true
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
stackframe@1.3.4:
resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
@ -8479,6 +8531,47 @@ packages:
peerDependencies:
vitest: ^3.0.0 || ^4.0.0
vitest@4.1.4:
resolution: {integrity: sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==}
engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@opentelemetry/api': ^1.9.0
'@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
'@vitest/browser-playwright': 4.1.4
'@vitest/browser-preview': 4.1.4
'@vitest/browser-webdriverio': 4.1.4
'@vitest/coverage-istanbul': 4.1.4
'@vitest/coverage-v8': 4.1.4
'@vitest/ui': 4.1.4
happy-dom: '*'
jsdom: '*'
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
'@opentelemetry/api':
optional: true
'@types/node':
optional: true
'@vitest/browser-playwright':
optional: true
'@vitest/browser-preview':
optional: true
'@vitest/browser-webdriverio':
optional: true
'@vitest/coverage-istanbul':
optional: true
'@vitest/coverage-v8':
optional: true
'@vitest/ui':
optional: true
happy-dom:
optional: true
jsdom:
optional: true
void-elements@3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
@ -8558,6 +8651,11 @@ packages:
engines: {node: '>= 8'}
hasBin: true
why-is-node-running@2.3.0:
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
hasBin: true
word-wrap@1.2.5:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'}
@ -8905,6 +9003,60 @@ snapshots:
- typescript
- vitest
'@antfu/eslint-config@8.2.0(@eslint-react/eslint-plugin@3.0.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@next/eslint-plugin-next@16.2.3)(@typescript-eslint/rule-tester@8.57.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2))(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@vue/compiler-sfc@3.5.31)(eslint-plugin-react-refresh@0.5.2(eslint@10.2.0(jiti@2.6.1)))(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.20.0))(typescript@6.0.2)(vitest@4.1.4)':
dependencies:
'@antfu/install-pkg': 1.1.0
'@clack/prompts': 1.2.0
'@e18e/eslint-plugin': 0.3.0(eslint@10.2.0(jiti@2.6.1))(oxlint@1.60.0(oxlint-tsgolint@0.20.0))
'@eslint-community/eslint-plugin-eslint-comments': 4.7.1(eslint@10.2.0(jiti@2.6.1))
'@eslint/markdown': 8.0.1
'@stylistic/eslint-plugin': 5.10.0(eslint@10.2.0(jiti@2.6.1))
'@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)
'@typescript-eslint/parser': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)
'@vitest/eslint-plugin': 1.6.15(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)(vitest@4.1.4)
ansis: 4.2.0
cac: 7.0.0
eslint: 10.2.0(jiti@2.6.1)
eslint-config-flat-gitignore: 2.3.0(eslint@10.2.0(jiti@2.6.1))
eslint-flat-config-utils: 3.1.0
eslint-merge-processors: 2.0.0(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-antfu: 3.2.2(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-command: 3.5.2(@typescript-eslint/rule-tester@8.57.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2))(@typescript-eslint/utils@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-import-lite: 0.6.0(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-jsdoc: 62.9.0(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-jsonc: 3.1.2(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-n: 17.24.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)
eslint-plugin-no-only-tests: 3.3.0
eslint-plugin-perfectionist: 5.8.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)
eslint-plugin-pnpm: 1.6.0(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-regexp: 3.1.0(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-toml: 1.3.1(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-unicorn: 64.0.0(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-unused-imports: 4.4.1(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))
eslint-plugin-vue: 10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.2.0(jiti@2.6.1)))(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.2.0(jiti@2.6.1)))
eslint-plugin-yml: 3.3.1(eslint@10.2.0(jiti@2.6.1))
eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.31)(eslint@10.2.0(jiti@2.6.1))
globals: 17.5.0
local-pkg: 1.1.2
parse-gitignore: 2.0.0
toml-eslint-parser: 1.0.3
vue-eslint-parser: 10.4.0(eslint@10.2.0(jiti@2.6.1))
yaml-eslint-parser: 2.0.0
optionalDependencies:
'@eslint-react/eslint-plugin': 3.0.0(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)
'@next/eslint-plugin-next': 16.2.3
eslint-plugin-react-refresh: 0.5.2(eslint@10.2.0(jiti@2.6.1))
transitivePeerDependencies:
- '@eslint/json'
- '@typescript-eslint/rule-tester'
- '@typescript-eslint/typescript-estree'
- '@typescript-eslint/utils'
- '@vue/compiler-sfc'
- oxlint
- supports-color
- typescript
- vitest
'@antfu/install-pkg@1.1.0':
dependencies:
package-manager-detector: 1.6.0
@ -12043,6 +12195,21 @@ snapshots:
tinyrainbow: 3.1.0
vitest: '@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)'
'@vitest/coverage-v8@4.1.4(vitest@4.1.4)':
dependencies:
'@bcoe/v8-coverage': 1.0.2
'@vitest/utils': 4.1.4
ast-v8-to-istanbul: 1.0.0
istanbul-lib-coverage: 3.2.2
istanbul-lib-report: 3.0.1
istanbul-reports: 3.2.0
magicast: 0.5.2
obug: 2.1.1
std-env: 4.0.0
tinyrainbow: 3.1.0
vitest: 4.1.4(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(happy-dom@20.9.0)
optional: true
'@vitest/eslint-plugin@1.6.15(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(@voidzero-dev/vite-plus-test@0.1.18)(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)':
dependencies:
'@typescript-eslint/scope-manager': 8.58.2
@ -12055,6 +12222,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vitest/eslint-plugin@1.6.15(@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)(vitest@4.1.4)':
dependencies:
'@typescript-eslint/scope-manager': 8.58.2
'@typescript-eslint/utils': 8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)
eslint: 10.2.0(jiti@2.6.1)
optionalDependencies:
'@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.2.0(jiti@2.6.1))(typescript@6.0.2)
typescript: 6.0.2
vitest: 4.1.4(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(happy-dom@20.9.0)
transitivePeerDependencies:
- supports-color
'@vitest/expect@3.2.4':
dependencies:
'@types/chai': 5.2.3
@ -12063,6 +12242,25 @@ snapshots:
chai: 5.3.3
tinyrainbow: 2.0.0
'@vitest/expect@4.1.4':
dependencies:
'@standard-schema/spec': 1.1.0
'@types/chai': 5.2.3
'@vitest/spy': 4.1.4
'@vitest/utils': 4.1.4
chai: 6.2.2
tinyrainbow: 3.1.0
optional: true
'@vitest/mocker@4.1.4(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))':
dependencies:
'@vitest/spy': 4.1.4
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)'
optional: true
'@vitest/pretty-format@3.2.4':
dependencies:
tinyrainbow: 2.0.0
@ -12071,10 +12269,27 @@ snapshots:
dependencies:
tinyrainbow: 3.1.0
'@vitest/runner@4.1.4':
dependencies:
'@vitest/utils': 4.1.4
pathe: 2.0.3
optional: true
'@vitest/snapshot@4.1.4':
dependencies:
'@vitest/pretty-format': 4.1.4
'@vitest/utils': 4.1.4
magic-string: 0.30.21
pathe: 2.0.3
optional: true
'@vitest/spy@3.2.4':
dependencies:
tinyspy: 4.0.4
'@vitest/spy@4.1.4':
optional: true
'@vitest/utils@3.2.4':
dependencies:
'@vitest/pretty-format': 3.2.4
@ -12509,6 +12724,9 @@ snapshots:
loupe: 3.2.1
pathval: 2.0.1
chai@6.2.2:
optional: true
chalk@4.1.1:
dependencies:
ansi-styles: 4.3.0
@ -13335,7 +13553,7 @@ snapshots:
jsonc-eslint-parser: 3.1.0
pathe: 2.0.3
pnpm-workspace-yaml: 1.6.0
tinyglobby: 0.2.15
tinyglobby: 0.2.16
yaml: 2.8.3
yaml-eslint-parser: 2.0.0
@ -13703,6 +13921,9 @@ snapshots:
expand-template@2.0.3:
optional: true
expect-type@1.3.0:
optional: true
exsolve@1.0.8: {}
extend@3.0.2: {}
@ -16092,6 +16313,9 @@ snapshots:
'@shikijs/vscode-textmate': 10.0.2
'@types/hast': 3.0.4
siginfo@2.0.0:
optional: true
simple-concat@1.0.1:
optional: true
@ -16174,6 +16398,9 @@ snapshots:
srvx@0.11.15: {}
stackback@0.0.2:
optional: true
stackframe@1.3.4: {}
state-local@1.0.7: {}
@ -16815,6 +17042,36 @@ snapshots:
moo-color: 1.0.3
vitest: '@voidzero-dev/vite-plus-test@0.1.18(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)'
vitest@4.1.4(@types/node@25.6.0)(@vitest/coverage-v8@4.1.4)(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))(happy-dom@20.9.0):
dependencies:
'@vitest/expect': 4.1.4
'@vitest/mocker': 4.1.4(@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3))
'@vitest/pretty-format': 4.1.4
'@vitest/runner': 4.1.4
'@vitest/snapshot': 4.1.4
'@vitest/spy': 4.1.4
'@vitest/utils': 4.1.4
es-module-lexer: 2.0.0
expect-type: 1.3.0
magic-string: 0.30.21
obug: 2.1.1
pathe: 2.0.3
picomatch: 4.0.4
std-env: 4.0.0
tinybench: 2.9.0
tinyexec: 1.0.4
tinyglobby: 0.2.16
tinyrainbow: 3.1.0
vite: '@voidzero-dev/vite-plus-core@0.1.18(@types/node@25.6.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@6.0.2)(yaml@2.8.3)'
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 25.6.0
'@vitest/coverage-v8': 4.1.4(vitest@4.1.4)
happy-dom: 20.9.0
transitivePeerDependencies:
- msw
optional: true
void-elements@3.1.0: {}
vscode-jsonrpc@8.2.0: {}
@ -16905,6 +17162,12 @@ snapshots:
dependencies:
isexe: 2.0.0
why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2
optional: true
word-wrap@1.2.5: {}
wrappy@1.0.2: {}

View File

@ -4,93 +4,93 @@ packages:
- sdks/nodejs-client
- packages/*
allowBuilds:
"@parcel/watcher": false
'@parcel/watcher': false
canvas: false
esbuild: false
sharp: false
blockExoticSubdeps: true
catalog:
"@amplitude/analytics-browser": 2.39.0
"@amplitude/plugin-session-replay-browser": 1.27.7
"@antfu/eslint-config": 8.2.0
"@base-ui/react": 1.4.0
"@chromatic-com/storybook": 5.1.2
"@cucumber/cucumber": 12.8.0
"@date-fns/tz": 1.4.1
"@egoist/tailwindcss-icons": 1.9.2
"@emoji-mart/data": 1.2.1
"@eslint-react/eslint-plugin": 3.0.0
"@eslint/js": 10.0.1
"@floating-ui/react": 0.27.19
"@formatjs/intl-localematcher": 0.8.3
"@headlessui/react": 2.2.10
"@heroicons/react": 2.2.0
"@hono/node-server": 1.19.14
"@iconify-json/heroicons": 1.2.3
"@iconify-json/ri": 1.2.10
"@lexical/code": 0.43.0
"@lexical/link": 0.43.0
"@lexical/list": 0.43.0
"@lexical/react": 0.43.0
"@lexical/selection": 0.43.0
"@lexical/text": 0.43.0
"@lexical/utils": 0.43.0
"@mdx-js/loader": 3.1.1
"@mdx-js/react": 3.1.1
"@mdx-js/rollup": 3.1.1
"@monaco-editor/react": 4.7.0
"@next/eslint-plugin-next": 16.2.3
"@next/mdx": 16.2.3
"@orpc/client": 1.13.14
"@orpc/contract": 1.13.14
"@orpc/openapi-client": 1.13.14
"@orpc/tanstack-query": 1.13.14
"@playwright/test": 1.59.1
"@remixicon/react": 4.9.0
"@rgrove/parse-xml": 4.2.0
"@sentry/react": 10.48.0
"@storybook/addon-docs": 10.3.5
"@storybook/addon-links": 10.3.5
"@storybook/addon-onboarding": 10.3.5
"@storybook/addon-themes": 10.3.5
"@storybook/nextjs-vite": 10.3.5
"@storybook/react": 10.3.5
"@streamdown/math": 1.0.2
"@svgdotjs/svg.js": 3.2.5
"@t3-oss/env-nextjs": 0.13.11
"@tailwindcss/postcss": 4.2.2
"@tailwindcss/typography": 0.5.19
"@tailwindcss/vite": 4.2.2
"@tanstack/eslint-plugin-query": 5.99.0
"@tanstack/react-devtools": 0.10.2
"@tanstack/react-form": 1.29.0
"@tanstack/react-form-devtools": 0.2.21
"@tanstack/react-query": 5.99.0
"@tanstack/react-query-devtools": 5.99.0
"@tanstack/react-virtual": 3.13.23
"@testing-library/dom": 10.4.1
"@testing-library/jest-dom": 6.9.1
"@testing-library/react": 16.3.2
"@testing-library/user-event": 14.6.1
'@amplitude/analytics-browser': 2.39.0
'@amplitude/plugin-session-replay-browser': 1.27.7
'@antfu/eslint-config': 8.2.0
'@base-ui/react': 1.4.0
'@chromatic-com/storybook': 5.1.2
'@cucumber/cucumber': 12.8.0
'@date-fns/tz': 1.4.1
'@egoist/tailwindcss-icons': 1.9.2
'@emoji-mart/data': 1.2.1
'@eslint-react/eslint-plugin': 3.0.0
'@eslint/js': 10.0.1
'@floating-ui/react': 0.27.19
'@formatjs/intl-localematcher': 0.8.3
'@headlessui/react': 2.2.10
'@heroicons/react': 2.2.0
'@hono/node-server': 1.19.14
'@iconify-json/heroicons': 1.2.3
'@iconify-json/ri': 1.2.10
'@lexical/code': 0.43.0
'@lexical/link': 0.43.0
'@lexical/list': 0.43.0
'@lexical/react': 0.43.0
'@lexical/selection': 0.43.0
'@lexical/text': 0.43.0
'@lexical/utils': 0.43.0
'@mdx-js/loader': 3.1.1
'@mdx-js/react': 3.1.1
'@mdx-js/rollup': 3.1.1
'@monaco-editor/react': 4.7.0
'@next/eslint-plugin-next': 16.2.3
'@next/mdx': 16.2.3
'@orpc/client': 1.13.14
'@orpc/contract': 1.13.14
'@orpc/openapi-client': 1.13.14
'@orpc/tanstack-query': 1.13.14
'@playwright/test': 1.59.1
'@remixicon/react': 4.9.0
'@rgrove/parse-xml': 4.2.0
'@sentry/react': 10.48.0
'@storybook/addon-docs': 10.3.5
'@storybook/addon-links': 10.3.5
'@storybook/addon-onboarding': 10.3.5
'@storybook/addon-themes': 10.3.5
'@storybook/nextjs-vite': 10.3.5
'@storybook/react': 10.3.5
'@streamdown/math': 1.0.2
'@svgdotjs/svg.js': 3.2.5
'@t3-oss/env-nextjs': 0.13.11
'@tailwindcss/postcss': 4.2.2
'@tailwindcss/typography': 0.5.19
'@tailwindcss/vite': 4.2.2
'@tanstack/eslint-plugin-query': 5.99.0
'@tanstack/react-devtools': 0.10.2
'@tanstack/react-form': 1.29.0
'@tanstack/react-form-devtools': 0.2.21
'@tanstack/react-query': 5.99.0
'@tanstack/react-query-devtools': 5.99.0
'@tanstack/react-virtual': 3.13.23
'@testing-library/dom': 10.4.1
'@testing-library/jest-dom': 6.9.1
'@testing-library/react': 16.3.2
'@testing-library/user-event': 14.6.1
'@tsdown/css': 0.21.8
"@tsslint/cli": 3.0.3
"@tsslint/compat-eslint": 3.0.3
"@tsslint/config": 3.0.3
"@types/js-cookie": 3.0.6
"@types/js-yaml": 4.0.9
"@types/negotiator": 0.6.4
"@types/node": 25.6.0
"@types/postcss-js": 4.1.0
"@types/qs": 6.15.0
"@types/react": 19.2.14
"@types/react-dom": 19.2.3
"@types/sortablejs": 1.15.9
"@typescript-eslint/eslint-plugin": 8.58.2
"@typescript-eslint/parser": 8.58.2
"@typescript/native-preview": 7.0.0-dev.20260413.1
"@vitejs/plugin-react": 6.0.1
"@vitejs/plugin-rsc": 0.5.24
"@vitest/coverage-v8": 4.1.4
'@tsslint/cli': 3.0.3
'@tsslint/compat-eslint': 3.0.3
'@tsslint/config': 3.0.3
'@types/js-cookie': 3.0.6
'@types/js-yaml': 4.0.9
'@types/negotiator': 0.6.4
'@types/node': 25.6.0
'@types/postcss-js': 4.1.0
'@types/qs': 6.15.0
'@types/react': 19.2.14
'@types/react-dom': 19.2.3
'@types/sortablejs': 1.15.9
'@typescript-eslint/eslint-plugin': 8.58.2
'@typescript-eslint/parser': 8.58.2
'@typescript/native-preview': 7.0.0-dev.20260413.1
'@vitejs/plugin-react': 6.0.1
'@vitejs/plugin-rsc': 0.5.24
'@vitest/coverage-v8': 4.1.4
abcjs: 6.6.2
agentation: 3.0.2
ahooks: 3.9.7
@ -200,8 +200,8 @@ catalog:
zustand: 5.0.12
catalogMode: prefer
overrides:
"@lexical/code": npm:lexical-code-no-prism@0.41.0
"@monaco-editor/loader": 1.7.0
'@lexical/code': npm:lexical-code-no-prism@0.41.0
'@monaco-editor/loader': 1.7.0
brace-expansion@>=2.0.0 <2.0.3: 2.0.3
canvas: ^3.2.2
dompurify@>=3.1.3 <=3.3.1: 3.3.2

View File

@ -1,5 +1,7 @@
import { defineConfig } from 'vite-plus'
export default defineConfig({
staged: {},
staged: {
'*': 'eslint --fix --pass-on-unpruned-suppressions',
},
})

2
web/.gitignore vendored
View File

@ -64,5 +64,3 @@ public/fallback-*.js
.vscode/settings.json
.vscode/mcp.json
.eslintcache

View File

@ -106,7 +106,7 @@ Open <http://localhost:6006> with your browser to see the result.
## Lint Code
If your IDE is VSCode, rename `web/.vscode/settings.example.json` to `web/.vscode/settings.json` for lint code setting.
If your IDE is VSCode, rename `.vscode/settings.example.json` to `.vscode/settings.json` for lint code setting.
Then follow the [Lint Documentation] to lint the code.

View File

@ -1,5 +1,6 @@
// @ts-check
import path from 'node:path'
import antfu, { GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_TESTS, GLOB_TS, GLOB_TSX, isInEditorEnv, isInGitHooksOrLintStaged } from '@antfu/eslint-config'
import pluginQuery from '@tanstack/eslint-plugin-query'
import md from 'eslint-markdown'
@ -32,11 +33,6 @@ export default antfu(
'react/no-unnecessary-use-prefix': 'error',
},
},
nextjs: {
overrides: {
'next/no-img-element': 'off',
},
},
ignores: ['public', 'types/doc-paths.ts', 'eslint-suppressions.json'],
typescript: {
overrides: {
@ -134,7 +130,8 @@ export default antfu(
},
settings: {
'better-tailwindcss': {
entryPoint: 'app/styles/globals.css',
cwd: import.meta.dirname,
entryPoint: path.resolve(import.meta.dirname, './app/styles/globals.css'),
},
},
},

View File

@ -34,10 +34,6 @@
"gen-icons": "pnpm --filter @dify/iconify-collections generate && node ./scripts/gen-icons.mjs && eslint --fix app/components/base/icons/src/",
"i18n:check": "tsx ./scripts/check-i18n.js",
"knip": "knip",
"lint": "eslint --cache --concurrency=auto",
"lint:ci": "eslint --cache --cache-strategy content --concurrency 2",
"lint:fix": "vp run lint --fix",
"lint:quiet": "vp run lint --quiet",
"lint:tss": "tsslint --project tsconfig.json",
"preinstall": "npx only-allow pnpm",
"refactor-component": "node ./scripts/refactor-component.js",

View File

@ -19,9 +19,6 @@ export default defineConfig(({ mode }) => {
|| process.argv.some(arg => arg.toLowerCase().includes('storybook'))
return {
staged: {
'*': 'eslint --fix --pass-on-unpruned-suppressions',
},
plugins: isTest
? [
nextStaticImageTestPlugin({ projectRoot }),