chore: migrate static checks to vp check (#38850)

This commit is contained in:
Stephen Zhou 2026-07-13 16:00:39 +08:00 committed by GitHub
parent b03385ffb0
commit e35187f376
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 62 additions and 86 deletions

View File

@ -126,8 +126,8 @@ For the current file being tested:
- [ ] Run full directory test: `pnpm test path/to/directory/`
- [ ] Check coverage report: `pnpm test:coverage`
- [ ] Run `pnpm lint:fix` on all test files
- [ ] Run `pnpm type-check`
- [ ] Run `pnpm check:fix`
- [ ] Run `pnpm check`
## Common Issues to Watch

View File

@ -169,19 +169,13 @@ jobs:
if: github.event_name != 'merge_group' && steps.frontend-contract-changes.outputs.any_changed == 'true'
run: pnpm --dir packages/contracts gen-api-contract
- name: Oxlint autofix
if: github.event_name != 'merge_group' && steps.web-changes.outputs.any_changed == 'true'
run: |
pnpm lint:oxlint:fix --prune-suppressions --quiet || true
- name: ESLint fallback autofix
if: github.event_name != 'merge_group' && steps.web-changes.outputs.any_changed == 'true'
run: |
pnpm lint:eslint:fix --quiet || true
run: pnpm lint:eslint:fix --quiet || true
- name: Format frontend files
- name: Vite+ static autofix
if: github.event_name != 'merge_group' && (steps.web-changes.outputs.any_changed == 'true' || steps.frontend-contract-changes.outputs.any_changed == 'true')
run: vp fmt
run: vp check --fix || true
- if: github.event_name != 'merge_group'
uses: autofix-ci/action@c5b2d67aa2274e7b5a18224e8171550871fc7e4a # v1.3.4

View File

@ -137,7 +137,7 @@ jobs:
ts-common-style:
name: TS Common
runs-on: depot-ubuntu-24.04
runs-on: depot-ubuntu-24.04-4
permissions:
checks: write
pull-requests: read
@ -176,17 +176,9 @@ jobs:
if: steps.changed-files.outputs.any_changed == 'true'
uses: ./.github/actions/setup-web
- name: Format check
- name: Static check
if: steps.changed-files.outputs.any_changed == 'true'
run: vp fmt --check
- name: Style check
if: steps.changed-files.outputs.any_changed == 'true'
run: pnpm -w lint:ci
- name: Type check
if: steps.changed-files.outputs.any_changed == 'true'
run: pnpm -w type-check
run: pnpm -w check
superlinter:
name: SuperLinter

View File

@ -31,7 +31,7 @@ The codebase is split into:
## Language Style
- **Python**: Keep type hints on functions and attributes, and implement relevant special methods (e.g., `__repr__`, `__str__`). Prefer `TypedDict` over `dict` or `Mapping` for type safety and better code documentation.
- **TypeScript**: Use the strict config, format with `vp fmt`, run `pnpm lint` for Oxlint code checks plus ESLint non-code checks, run `pnpm type-check`, and avoid `any` types.
- **TypeScript**: Use the strict config, run `pnpm check` for formatting, Oxlint, ESLint non-code checks, and type checking, and avoid `any` types.
## General Practices

View File

@ -57,10 +57,8 @@ pnpm install # one-time
pnpm dev <command> [args...] # run CLI from source (no -- separator)
pnpm test # vitest
pnpm test:coverage # with coverage
pnpm -w type-check # repository-wide type check
pnpm -w lint # repository-wide lint
pnpm -w lint:fix # repository-wide lint fixes
vp fmt # format with Oxfmt
pnpm -w check # repository-wide static check
pnpm -w check:fix # repository-wide static fixes
pnpm build # production bundle (vp pack)
pnpm tree:gen # regenerate src/commands/tree.ts (registry)
pnpm tree:check # verify tree.ts is up-to-date with the fs
@ -72,7 +70,7 @@ Release binaries (5 platform targets, Bun-compiled) are produced by `pnpm build:
- Behavior tests run against real Hono mock at `test/fixtures/dify-mock/`. No `nock`, `msw`, or `fetchMock` — every test exercises real HTTP.
- Test files co-located: `foo.test.ts` next to `foo.ts`.
- Repository-wide type-check and lint, plus the full test suite, must be green before any commit.
- The repository-wide static check and full test suite must be green before any commit.
## Spec docs (`docs/specs/`)

View File

@ -306,10 +306,8 @@ expect(JSON.parse(out).workspaces).toHaveLength(2)
| `pnpm dev <cmd> [args]` | Run CLI from source during dev |
| `pnpm test` | Full vitest suite — run before every commit |
| `pnpm test:coverage` | Coverage report |
| `pnpm -w type-check` | Repository-wide TypeScript type check |
| `pnpm -w lint` | Repository-wide Oxlint and ESLint checks |
| `pnpm -w lint:fix` | Repository-wide Oxlint and ESLint fixes |
| `vp fmt` | Oxfmt formatting and import sorting |
| `pnpm -w check` | Repository-wide static check |
| `pnpm -w check:fix` | Repository-wide static fixes |
| `pnpm build` | Production bundle (`vp pack`) |
| `pnpm tree:gen` | Regenerate `src/commands/tree.ts` (registry) |
| `pnpm tree:check` | Verify `tree.ts` matches the filesystem |
@ -333,7 +331,7 @@ The repository runs Vite+ Oxlint as the primary code-quality linter, an explicit
| `unicorn/no-new-array` | Use `Array.from({ length: n })` not `new Array(n)` |
| `noUncheckedIndexedAccess` (tsc) | `arr[i]` is `T \| undefined`; guard before use |
Run `pnpm -w lint:fix` for Oxlint and ESLint fixes, then `vp fmt` so Oxfmt produces the final layout.
Run `pnpm -w check:fix` for Oxlint, ESLint, TypeScript, and Oxfmt fixes and diagnostics.
---

View File

@ -12,6 +12,7 @@ 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.
@ -385,7 +386,7 @@ export default defineConfig([
plugins: {
markdown,
'markdown-preferences': markdownPreferences,
md,
md: mdPlugin,
},
rules: {
'markdown/fenced-code-language': 'off',

View File

@ -91,7 +91,7 @@ export const lintConfig = {
reportUnusedDisableDirectives: 'warn',
respectEslintDisableDirectives: false,
typeAware: true,
typeCheck: false,
typeCheck: true,
},
settings: {
'better-tailwindcss': {

View File

@ -3,15 +3,10 @@
"private": true,
"type": "module",
"scripts": {
"check": "vp check && pnpm lint:eslint",
"check:fix": "pnpm lint:eslint:fix && vp check --fix",
"dev": "concurrently -k -n vinext,proxy \"vp run dify-web#dev:vinext\" \"vp run dify-web#dev:proxy\"",
"fmt": "vp fmt",
"fmt:check": "vp fmt --check",
"prepare": "vp config",
"type-check": "vp run -r type-check",
"lint": "pnpm lint:oxlint && pnpm lint:eslint",
"lint:ci": "pnpm lint:oxlint && pnpm lint:eslint",
"lint:fix": "pnpm lint:oxlint:fix && pnpm lint:eslint:fix",
"lint:quiet": "pnpm lint:oxlint:quiet && pnpm lint:eslint:quiet",
"lint:oxlint": "vp lint",
"lint:oxlint:fix": "vp lint --fix",
"lint:oxlint:quiet": "vp lint --quiet",

1
packages/dify-ui/src/styles.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module '*.css'

View File

@ -3,6 +3,13 @@
"compilerOptions": {
"types": ["vite-plus/test/globals", "vite-plus/test/matchers"]
},
"include": ["src/**/*.ts", "src/**/*.tsx", "vite.config.ts"],
"include": [
".storybook/**/*.ts",
".storybook/**/*.tsx",
"src/**/*.ts",
"src/**/*.tsx",
"vite.config.ts",
"vitest.config.ts"
],
"exclude": ["node_modules", "dist", "storybook-static", "coverage"]
}

View File

@ -4,10 +4,9 @@ import { lintConfig } from './lint.config'
const lintFiles = '*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'
const eslintFiles = '*.{json,jsonc,json5,md,yml,yaml,toml}'
const formatOnlyFiles = '*.{mdx,css,scss,less,html,vue,svelte,gql,graphql,hbs,handlebars}'
const lintFix = 'vp lint --fix --no-error-on-unmatched-pattern'
const checkFix = 'vp check --fix --no-error-on-unmatched-pattern'
const eslintFix =
'eslint --fix --pass-on-unpruned-suppressions --no-error-on-unmatched-pattern --no-warn-ignored'
const format = 'vp fmt --no-error-on-unmatched-pattern'
const nonFrontendIgnores = [
'.agents/**',
@ -47,9 +46,9 @@ const formatterUnstableInputs = ['web/app/components/develop/template/*.mdx']
export default defineConfig({
lint: lintConfig,
staged: {
[lintFiles]: [lintFix, format],
[eslintFiles]: [eslintFix, format],
[formatOnlyFiles]: format,
[lintFiles]: checkFix,
[eslintFiles]: [eslintFix, checkFix],
[formatOnlyFiles]: checkFix,
},
fmt: {
ignorePatterns: [...nonFrontendIgnores, ...generatedIgnores, ...formatterUnstableInputs],

View File

@ -1,4 +1,4 @@
import type { Preview } from '@storybook/react'
import type { Decorator, Preview } from '@storybook/react'
import type { Resource } from 'i18next'
import { ToastHost } from '@langgenius/dify-ui/toast'
import { withThemeByDataAttribute } from '@storybook/addon-themes'
@ -24,7 +24,7 @@ const storyResources: Resource = {
},
}
export const decorators = [
export const decorators: Decorator[] = [
withThemeByDataAttribute({
themes: {
light: 'light',

View File

@ -37,7 +37,6 @@ describe('useDocumentActions', () => {
beforeEach(() => {
vi.clearAllMocks()
// Setup all mocks with default values
const createMockMutation = () => ({
mutateAsync: mockMutateAsync,
isPending: false,

View File

@ -1,50 +1,38 @@
# Format and Lint Guide
# Static Check Guide
We use Vite+ Oxfmt for formatting, Vite+ Oxlint for code-quality linting, ESLint for non-code file types that Oxlint cannot parse, and TypeScript for type safety.
Vite+ provides the primary static check through `vp check`, which combines Oxfmt formatting, Oxlint code-quality rules, and TypeScript diagnostics. The root command also runs ESLint for non-code file types that Oxlint cannot parse.
## Format
## Check
Format the supported frontend and TypeScript workspace files from the repository root:
Run the complete repository check from the root:
```sh
vp fmt
pnpm check
```
Check formatting without writing changes:
Apply safe fixes before running the same checks:
```sh
vp fmt --check
pnpm check:fix
```
The shared formatter options and ignore boundaries live in the root `vite.config.ts`.
Editor format-on-save must point Oxc at that file so local edits match the commit hook and CI.
CI and local development use the same root `vite.config.ts` configuration.
## Lint
Run the repository lint from the root:
For a smaller code scope, pass paths directly to Vite+:
```sh
pnpm lint
vp check web/app/components packages/dify-ui/src/button
vp check --fix web/app/components packages/dify-ui/src/button
```
Run the two lint paths separately when targeting a smaller scope:
Run the ESLint fallback separately when targeting JSON, JSONC, JSON5, YAML, TOML, or Markdown:
```sh
pnpm lint:oxlint web/app/components packages/dify-ui/src/button
pnpm lint:eslint package.json pnpm-workspace.yaml web/docs
```
Apply safe fixes, then format the result:
```sh
pnpm lint:oxlint:fix web/app/components
pnpm lint:eslint:fix package.json pnpm-workspace.yaml web/docs
vp fmt web/app/components
```
Use `pnpm lint:quiet` to hide warnings from both linters. Oxlint runs in parallel by default, and the root ESLint scripts enable automatic concurrency.
The default and CI lint commands do not pass file lists on the command line. Oxlint's repository scope is defined by `lint.config.ts` `ignorePatterns`, and ESLint's scope is defined by `eslint.config.mjs` global ignores. The individual linter commands above accept explicit paths for ad hoc local subsets.
Oxlint and Vite+ type-check scope is defined by `lint.config.ts` `ignorePatterns`, and ESLint's scope is defined by `eslint.config.mjs` global ignores.
The primary rule baseline lives in `lint.config.ts` and is connected through the root `vite.config.ts` `lint` block. Oxlint-native rules are preferred, and compatible ESLint rules can run through Oxlint's `jsPlugins` support. The rules are explicit snapshots of the ESLint configurations that were active at migration time. Do not import an upstream preset wholesale: enable a new rule intentionally and review its existing violations first.
@ -52,13 +40,13 @@ The non-code baseline and its repository-wide file scope live in `eslint.config.
### Auto-fix Workflow
Configure the Oxc and ESLint editor extensions to apply their respective fixes on save. The commit hook runs `vp staged`: JavaScript and TypeScript pass through Oxlint and Oxfmt, while data and Markdown files pass through ESLint and Oxfmt. The autofix workflow also prunes resolved bulk suppressions.
Configure the Oxc and ESLint editor extensions to apply their respective fixes on save. The commit hook runs `vp staged`, which delegates staged files to `vp check --fix` and adds the ESLint fallback for non-code files. The autofix workflow uses the same combined Vite+ check.
Always review automatic fixes before committing. JS plugins are allowed to provide fixes, and their behavior is not necessarily identical to a native Oxlint rule.
### Type-aware Linting
The root configuration enables `typeAware` without enabling Oxlint's full `typeCheck` diagnostics. This preserves the Node SDK's existing type-aware lint rules without making lint duplicate the repository type-check task.
The root configuration enables both `typeAware` and `typeCheck`, so `vp check` runs type-aware rules and full TypeScript diagnostics through the TypeScript Go toolchain.
The web package still runs its existing TSSLint rule separately:
@ -66,10 +54,10 @@ The web package still runs its existing TSSLint rule separately:
pnpm --dir web lint:tss
```
Run the regular type check before committing or pushing:
Run the complete static check before committing or pushing:
```sh
pnpm type-check
pnpm check
```
### Bulk Suppressions
@ -99,8 +87,8 @@ ESLint is intentionally limited to non-code files. The remaining limitations and
| Area | Current status |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Code-only fallback rules | ESLint globally ignores all code files. Six core fallback rules, JS `dot-notation`, and other code-only ESLint checks are listed only in comments rather than executable configuration. |
| Declaration files | Oxlint excludes declaration files and ESLint no longer processes code. The former 223-rule declaration snapshot and CLI declaration import restriction are not enforced; TypeScript still checks these files. |
| Generated contracts | Both linters ignore `packages/contracts/**`; Oxfmt remains the only staged quality step for the contracts package. |
| Declaration files | Oxlint excludes declaration files and ESLint no longer processes code. The former 223-rule declaration snapshot and CLI declaration import restriction are not enforced. |
| Generated contracts | Both linters and Vite+ type checking ignore `packages/contracts/**`; Oxfmt remains the only staged quality step for the contracts package. |
| Non-JavaScript formats | Oxlint plugins cannot provide custom parsers or file languages. ESLint covers JSON, JSONC, YAML, TOML, and Markdown semantic rules, while Oxfmt remains responsible for their formatting. |
| Markdown code blocks | ESLint validates the Markdown document, but fenced JavaScript and TypeScript blocks are not passed through the former overlapping preset. This remains deferred rather than duplicating the Oxlint rule set. |
| Override-scoped settings | The three Dify UI Tailwind rules are disabled with the rest of ESLint's code path. Oxlint still applies the web `react-x.additionalStateHooks` setting globally because it cannot scope settings to an override. |
@ -114,14 +102,14 @@ Prefer a native Oxlint rule. If none exists, verify that the rule works through
For overlay import policy and composition rules, see [Overlay Guide].
## Type Check
## Type Checking
You should be able to see suggestions from TypeScript in your editor for all open files.
Run the repository type check from the root:
Type checking is part of the repository check:
```sh
pnpm type-check
pnpm check
```
Type checking is powered by [`tsgo`] (the native TypeScript 7 compiler), which is significantly faster than `tsc`.

View File

@ -18,7 +18,7 @@
"dev:proxy": "dev-proxy --config ./dev-proxy.config.ts --env-file ./.env.local",
"dev:vinext": "vinext dev",
"gen-doc-paths": "tsx ./scripts/gen-doc-paths.ts && vp fmt types/doc-paths.ts",
"gen-icons": "pnpm --filter @dify/iconify-collections generate && node ./scripts/gen-icons.mjs && pnpm -w lint:oxlint:fix -- web/app/components/base/icons/src/ && vp fmt app/components/base/icons/src/",
"gen-icons": "pnpm --filter @dify/iconify-collections generate && node ./scripts/gen-icons.mjs && pnpm -w exec vp check --fix web/app/components/base/icons/src/",
"i18n:check": "tsx ./scripts/check-i18n.js",
"i18n:migrate-selectors": "tsx ./scripts/migrate-i18n-selectors.ts",
"i18n:prune-unused": "tsx ./scripts/prune-unused-i18n.ts",

View File

@ -13,6 +13,8 @@
},
"include": [
"next-env.d.ts",
".storybook/**/*.ts",
".storybook/**/*.tsx",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",

View File

@ -1,3 +1,5 @@
declare module '*.css'
declare module '*.svg' {
const value: any
export default value