chore: workspace level typecheck (#35329)

This commit is contained in:
Stephen Zhou
2026-04-16 22:42:04 +08:00
committed by GitHub
parent c966e281d4
commit 4289cb2634
44 changed files with 236 additions and 294 deletions

View File

@@ -77,6 +77,8 @@ jobs:
with: with:
files: | files: |
web/** web/**
e2e/**
sdks/nodejs-client/**
packages/** packages/**
package.json package.json
pnpm-lock.yaml pnpm-lock.yaml
@@ -112,7 +114,7 @@ jobs:
- name: Web type check - name: Web type check
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
working-directory: ./web working-directory: .
run: vp run type-check run: vp run type-check
- name: Web dead code check - name: Web dead code check

View File

@@ -64,36 +64,8 @@ if $web_modified; then
echo "Running ESLint on web module" echo "Running ESLint on web module"
if git diff --cached --quiet -- 'web/**/*.ts' 'web/**/*.tsx'; then
web_ts_modified=false
else
ts_diff_status=$?
if [ $ts_diff_status -eq 1 ]; then
web_ts_modified=true
else
echo "Unable to determine staged TypeScript changes (git exit code: $ts_diff_status)."
exit $ts_diff_status
fi
fi
cd ./web || exit 1 cd ./web || exit 1
vp staged vp staged
if $web_ts_modified; then
echo "Running TypeScript type-check:tsgo"
if ! npm run type-check:tsgo; then
echo "Type check failed. Please run 'npm run type-check:tsgo' to fix the errors."
exit 1
fi
else
echo "No staged TypeScript changes detected, skipping type-check:tsgo"
fi
echo "Running knip"
if ! npm run knip; then
echo "Knip check failed. Please run 'npm run knip' to fix the errors."
exit 1
fi
cd ../ cd ../
fi fi

View File

@@ -11,9 +11,11 @@
"e2e:install": "playwright install --with-deps chromium", "e2e:install": "playwright install --with-deps chromium",
"e2e:middleware:down": "tsx ./scripts/setup.ts middleware-down", "e2e:middleware:down": "tsx ./scripts/setup.ts middleware-down",
"e2e:middleware:up": "tsx ./scripts/setup.ts middleware-up", "e2e:middleware:up": "tsx ./scripts/setup.ts middleware-up",
"e2e:reset": "tsx ./scripts/setup.ts reset" "e2e:reset": "tsx ./scripts/setup.ts reset",
"type-check": "tsc"
}, },
"devDependencies": { "devDependencies": {
"@dify/tsconfig": "workspace:*",
"@cucumber/cucumber": "catalog:", "@cucumber/cucumber": "catalog:",
"@playwright/test": "catalog:", "@playwright/test": "catalog:",
"@types/node": "catalog:", "@types/node": "catalog:",

View File

@@ -17,12 +17,10 @@ const parseArgs = (argv: string[]): RunOptions => {
let headed = false let headed = false
const forwardArgs: string[] = [] const forwardArgs: string[] = []
for (let index = 0; index < argv.length; index += 1) { for (const [index, arg] of argv.entries()) {
const arg = argv[index]
if (arg === '--') { if (arg === '--') {
forwardArgs.push(...argv.slice(index + 1)) forwardArgs.push(...argv.slice(index + 1))
break return { forwardArgs, full, headed }
} }
if (arg === '--full') { if (arg === '--full') {
@@ -38,11 +36,7 @@ const parseArgs = (argv: string[]): RunOptions => {
forwardArgs.push(arg) forwardArgs.push(arg)
} }
return { return { forwardArgs, full, headed }
forwardArgs,
full,
headed,
}
} }
const hasCustomTags = (forwardArgs: string[]) => const hasCustomTags = (forwardArgs: string[]) =>

View File

@@ -1,16 +1,9 @@
{ {
"extends": "@dify/tsconfig/node.json",
"compilerOptions": { "compilerOptions": {
"target": "ES2023",
"lib": ["ES2023", "DOM"], "lib": ["ES2023", "DOM"],
"module": "ESNext",
"moduleResolution": "Bundler",
"allowJs": false, "allowJs": false,
"resolveJsonModule": true,
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"types": ["node", "@playwright/test", "@cucumber/cucumber"], "types": ["node", "@playwright/test", "@cucumber/cucumber"],
"isolatedModules": true,
"verbatimModuleSyntax": true "verbatimModuleSyntax": true
}, },
"include": ["./**/*.ts"], "include": ["./**/*.ts"],

View File

@@ -2,7 +2,8 @@
"name": "dify", "name": "dify",
"private": true, "private": true,
"scripts": { "scripts": {
"prepare": "vp config" "prepare": "vp config",
"type-check": "vp run -r type-check"
}, },
"devDependencies": { "devDependencies": {
"vite": "catalog:", "vite": "catalog:",

View File

@@ -19,6 +19,11 @@
"tailwind-merge": "catalog:" "tailwind-merge": "catalog:"
}, },
"devDependencies": { "devDependencies": {
"tailwindcss": "catalog:" "@dify/tsconfig": "workspace:*",
"tailwindcss": "catalog:",
"typescript": "catalog:"
},
"scripts": {
"type-check": "tsc"
} }
} }

View File

@@ -1,11 +1,7 @@
{ {
"extends": "@dify/tsconfig/base.json",
"compilerOptions": { "compilerOptions": {
"target": "ES2022", "noEmit": false,
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true, "declaration": true,
"declarationMap": true, "declarationMap": true,
"sourceMap": true, "sourceMap": true,

View File

@@ -7,12 +7,14 @@
"migrate-no-unchecked-indexed-access": "./bin/migrate-no-unchecked-indexed-access.js" "migrate-no-unchecked-indexed-access": "./bin/migrate-no-unchecked-indexed-access.js"
}, },
"scripts": { "scripts": {
"build": "vp pack" "build": "vp pack",
"type-check": "tsc"
}, },
"dependencies": { "dependencies": {
"typescript": "catalog:" "typescript": "catalog:"
}, },
"devDependencies": { "devDependencies": {
"@dify/tsconfig": "workspace:*",
"@types/node": "catalog:", "@types/node": "catalog:",
"vite": "catalog:", "vite": "catalog:",
"vite-plus": "catalog:" "vite-plus": "catalog:"

View File

@@ -34,7 +34,8 @@ let exitCode = 0
try { try {
await main() await main()
exitCode = process.exitCode ?? 0 const currentExitCode = process.exitCode
exitCode = typeof currentExitCode === 'number' ? currentExitCode : 0
} }
catch (error) { catch (error) {
console.error(error instanceof Error ? error.message : error) console.error(error instanceof Error ? error.message : error)

View File

@@ -0,0 +1,3 @@
{
"extends": "@dify/tsconfig/node.json"
}

View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"esModuleInterop": true,
"skipLibCheck": true,
"target": "es2022",
"allowJs": true,
"resolveJsonModule": true,
"moduleDetection": "force",
"isolatedModules": true,
"verbatimModuleSyntax": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"module": "preserve",
"noEmit": true
}
}

View File

@@ -0,0 +1,10 @@
{
"extends": "./web.json",
"compilerOptions": {
"plugins": [
{
"name": "next"
}
]
}
}

View File

@@ -0,0 +1,7 @@
{
"extends": "./base.json",
"compilerOptions": {
"lib": ["es2022"],
"types": ["node"]
}
}

View File

@@ -0,0 +1,11 @@
{
"name": "@dify/tsconfig",
"version": "0.0.0-private",
"private": true,
"exports": {
"./base.json": "./base.json",
"./nextjs.json": "./nextjs.json",
"./node.json": "./node.json",
"./web.json": "./web.json"
}
}

View File

@@ -0,0 +1,7 @@
{
"extends": "./base.json",
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["es2022", "dom", "dom.iterable"]
}
}

20
pnpm-lock.yaml generated
View File

@@ -586,6 +586,9 @@ importers:
'@cucumber/cucumber': '@cucumber/cucumber':
specifier: 'catalog:' specifier: 'catalog:'
version: 12.8.0 version: 12.8.0
'@dify/tsconfig':
specifier: workspace:*
version: link:../packages/tsconfig
'@playwright/test': '@playwright/test':
specifier: 'catalog:' specifier: 'catalog:'
version: 1.59.1 version: 1.59.1
@@ -614,9 +617,15 @@ importers:
specifier: 'catalog:' specifier: 'catalog:'
version: 3.5.0 version: 3.5.0
devDependencies: devDependencies:
'@dify/tsconfig':
specifier: workspace:*
version: link:../tsconfig
tailwindcss: tailwindcss:
specifier: 'catalog:' specifier: 'catalog:'
version: 4.2.2 version: 4.2.2
typescript:
specifier: 'catalog:'
version: 6.0.2
packages/iconify-collections: packages/iconify-collections:
devDependencies: devDependencies:
@@ -630,6 +639,9 @@ importers:
specifier: 'catalog:' specifier: 'catalog:'
version: 6.0.2 version: 6.0.2
devDependencies: devDependencies:
'@dify/tsconfig':
specifier: workspace:*
version: link:../tsconfig
'@types/node': '@types/node':
specifier: 'catalog:' specifier: 'catalog:'
version: 25.6.0 version: 25.6.0
@@ -640,8 +652,13 @@ importers:
specifier: 'catalog:' specifier: 'catalog:'
version: 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) version: 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)
packages/tsconfig: {}
sdks/nodejs-client: sdks/nodejs-client:
devDependencies: devDependencies:
'@dify/tsconfig':
specifier: workspace:*
version: link:../../packages/tsconfig
'@eslint/js': '@eslint/js':
specifier: 'catalog:' specifier: 'catalog:'
version: 10.0.1(eslint@10.2.0(jiti@2.6.1)) version: 10.0.1(eslint@10.2.0(jiti@2.6.1))
@@ -991,6 +1008,9 @@ importers:
'@dify/iconify-collections': '@dify/iconify-collections':
specifier: workspace:* specifier: workspace:*
version: link:../packages/iconify-collections version: link:../packages/iconify-collections
'@dify/tsconfig':
specifier: workspace:*
version: link:../packages/tsconfig
'@egoist/tailwindcss-icons': '@egoist/tailwindcss-icons':
specifier: 'catalog:' specifier: 'catalog:'
version: 1.9.2(tailwindcss@4.2.2) version: 1.9.2(tailwindcss@4.2.2)

View File

@@ -48,13 +48,14 @@
"build": "vp pack", "build": "vp pack",
"lint": "eslint", "lint": "eslint",
"lint:fix": "eslint --fix", "lint:fix": "eslint --fix",
"type-check": "tsc -p tsconfig.json --noEmit", "type-check": "tsc",
"test": "vp test", "test": "vp test",
"test:coverage": "vp test --coverage", "test:coverage": "vp test --coverage",
"publish:check": "./scripts/publish.sh --dry-run", "publish:check": "./scripts/publish.sh --dry-run",
"publish:npm": "./scripts/publish.sh" "publish:npm": "./scripts/publish.sh"
}, },
"devDependencies": { "devDependencies": {
"@dify/tsconfig": "workspace:*",
"@eslint/js": "catalog:", "@eslint/js": "catalog:",
"@types/node": "catalog:", "@types/node": "catalog:",
"@typescript-eslint/eslint-plugin": "catalog:", "@typescript-eslint/eslint-plugin": "catalog:",

View File

@@ -14,8 +14,8 @@ describe("sse parsing", () => {
events.push(event); events.push(event);
} }
expect(events).toHaveLength(1); expect(events).toHaveLength(1);
expect(events[0].event).toBe("message"); expect(events[0]!.event).toBe("message");
expect(events[0].data).toEqual({ answer: "hi" }); expect(events[0]!.data).toEqual({ answer: "hi" });
}); });
it("handles multi-line data payloads", async () => { it("handles multi-line data payloads", async () => {
@@ -24,8 +24,8 @@ describe("sse parsing", () => {
for await (const event of parseSseStream(stream)) { for await (const event of parseSseStream(stream)) {
events.push(event); events.push(event);
} }
expect(events[0].raw).toBe("line1\nline2"); expect(events[0]!.raw).toBe("line1\nline2");
expect(events[0].data).toBe("line1\nline2"); expect(events[0]!.data).toBe("line1\nline2");
}); });
it("ignores comments and flushes the last event without a trailing separator", async () => { it("ignores comments and flushes the last event without a trailing separator", async () => {

View File

@@ -99,7 +99,7 @@ describe("File uploads", () => {
super(); super();
} }
_read() {} override _read() {}
append() {} append() {}

View File

@@ -1,18 +1,14 @@
{ {
"extends": "@dify/tsconfig/node.json",
"compilerOptions": { "compilerOptions": {
"target": "ES2022", "lib": ["ES2023", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "Bundler",
"rootDir": ".", "rootDir": ".",
"outDir": "dist", "outDir": "dist",
"noEmit": false,
"declaration": true, "declaration": true,
"declarationMap": true, "declarationMap": true,
"sourceMap": true, "sourceMap": true,
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"types": ["node"] "types": ["node"]
}, },
"include": ["src/**/*.ts", "tests/**/*.ts"] "include": ["src/**/*.ts", "tests/**/*.ts", "vite.config.ts"]
} }

View File

@@ -1,78 +0,0 @@
/**
* Tests for Array.prototype.toSpliced polyfill
*/
describe('toSpliced polyfill', () => {
let originalToSpliced: typeof Array.prototype.toSpliced
beforeEach(() => {
// Save original method
originalToSpliced = Array.prototype.toSpliced
})
afterEach(() => {
// Restore original method
// eslint-disable-next-line no-extend-native
Array.prototype.toSpliced = originalToSpliced
})
const applyPolyfill = () => {
// @ts-expect-error - intentionally deleting for test
delete Array.prototype.toSpliced
if (!Array.prototype.toSpliced) {
// eslint-disable-next-line no-extend-native
Array.prototype.toSpliced = function <T>(this: T[], start: number, deleteCount?: number, ...items: T[]): T[] {
const copy = this.slice()
copy.splice(start, deleteCount ?? copy.length - start, ...items)
return copy
}
}
}
it('should add toSpliced method when not available', () => {
applyPolyfill()
expect(typeof Array.prototype.toSpliced).toBe('function')
})
it('should return a new array without modifying the original', () => {
applyPolyfill()
const arr = [1, 2, 3, 4, 5]
const result = arr.toSpliced(1, 2)
expect(result).toEqual([1, 4, 5])
expect(arr).toEqual([1, 2, 3, 4, 5]) // original unchanged
})
it('should insert items at the specified position', () => {
applyPolyfill()
const arr: (number | string)[] = [1, 2, 3]
const result = arr.toSpliced(1, 0, 'a', 'b')
expect(result).toEqual([1, 'a', 'b', 2, 3])
})
it('should replace items at the specified position', () => {
applyPolyfill()
const arr: (number | string)[] = [1, 2, 3, 4, 5]
const result = arr.toSpliced(1, 2, 'a', 'b')
expect(result).toEqual([1, 'a', 'b', 4, 5])
})
it('should handle negative start index', () => {
applyPolyfill()
const arr = [1, 2, 3, 4, 5]
const result = arr.toSpliced(-2, 1)
expect(result).toEqual([1, 2, 3, 5])
})
it('should delete to end when deleteCount is omitted', () => {
applyPolyfill()
const arr = [1, 2, 3, 4, 5]
const result = arr.toSpliced(2)
expect(result).toEqual([1, 2])
})
})

View File

@@ -258,7 +258,8 @@ describe('CreateFromDSLModal', () => {
expect(getCreateButton())!.toBeDisabled() expect(getCreateButton())!.toBeDisabled()
}) })
ahooksMocks.handlers.findLast(item => Array.isArray(item.keys))?.handler() const latestHandlerAfterRemove = [...ahooksMocks.handlers].reverse().find(item => Array.isArray(item.keys))
latestHandlerAfterRemove?.handler()
expect(mockImportDSL).not.toHaveBeenCalled() expect(mockImportDSL).not.toHaveBeenCalled()
}) })
@@ -387,7 +388,8 @@ describe('CreateFromDSLModal', () => {
) )
expect(screen.getByText('apps-full'))!.toBeInTheDocument() expect(screen.getByText('apps-full'))!.toBeInTheDocument()
ahooksMocks.handlers.findLast(item => Array.isArray(item.keys))?.handler() const latestPlanLimitHandler = [...ahooksMocks.handlers].reverse().find(item => Array.isArray(item.keys))
latestPlanLimitHandler?.handler()
expect(mockImportDSL).toHaveBeenCalledTimes(1) expect(mockImportDSL).toHaveBeenCalledTimes(1)
}) })

View File

@@ -67,7 +67,7 @@ class ErrorBoundaryInner extends React.Component<
} }
} }
componentDidCatch(error: Error, errorInfo: ErrorInfo) { override componentDidCatch(error: Error, errorInfo: ErrorInfo) {
if (IS_DEV) { if (IS_DEV) {
console.error('ErrorBoundary caught an error:', error) console.error('ErrorBoundary caught an error:', error)
console.error('Error Info:', errorInfo) console.error('Error Info:', errorInfo)
@@ -82,7 +82,7 @@ class ErrorBoundaryInner extends React.Component<
this.props.onError(error, errorInfo) this.props.onError(error, errorInfo)
} }
componentDidUpdate(prevProps: any) { override componentDidUpdate(prevProps: any) {
const { resetKeys, resetOnPropsChange } = this.props const { resetKeys, resetOnPropsChange } = this.props
const { hasError } = this.state const { hasError } = this.state
@@ -98,7 +98,7 @@ class ErrorBoundaryInner extends React.Component<
this.props.onResetKeysChange(prevProps.resetKeys) this.props.onResetKeysChange(prevProps.resetKeys)
} }
render() { override render() {
const { hasError, error, errorInfo, errorCount } = this.state const { hasError, error, errorInfo, errorCount } = this.state
const { const {
fallback, fallback,

View File

@@ -17,12 +17,12 @@ export default class ErrorBoundary extends Component {
this.state = { hasError: false } this.state = { hasError: false }
} }
componentDidCatch(error: any, errorInfo: any) { override componentDidCatch(error: any, errorInfo: any) {
this.setState({ hasError: true }) this.setState({ hasError: true })
console.error(error, errorInfo) console.error(error, errorInfo)
} }
render() { override render() {
// eslint-disable-next-line ts/ban-ts-comment // eslint-disable-next-line ts/ban-ts-comment
// @ts-expect-error // @ts-expect-error
if (this.state.hasError) { if (this.state.hasError) {

View File

@@ -10,15 +10,15 @@ export class ContextBlockNode extends DecoratorNode<React.JSX.Element> {
__onAddContext: () => void __onAddContext: () => void
__canNotAddContext: boolean __canNotAddContext: boolean
static getType(): string { static override getType(): string {
return 'context-block' return 'context-block'
} }
static clone(node: ContextBlockNode): ContextBlockNode { static override clone(node: ContextBlockNode): ContextBlockNode {
return new ContextBlockNode(node.__datasets, node.__onAddContext, node.getKey(), node.__canNotAddContext) return new ContextBlockNode(node.__datasets, node.__onAddContext, node.getKey(), node.__canNotAddContext)
} }
isInline(): boolean { override isInline(): boolean {
return true return true
} }
@@ -30,17 +30,17 @@ export class ContextBlockNode extends DecoratorNode<React.JSX.Element> {
this.__canNotAddContext = canNotAddContext || false this.__canNotAddContext = canNotAddContext || false
} }
createDOM(): HTMLElement { override createDOM(): HTMLElement {
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('inline-flex', 'items-center', 'align-middle') div.classList.add('inline-flex', 'items-center', 'align-middle')
return div return div
} }
updateDOM(): false { override updateDOM(): false {
return false return false
} }
decorate(): React.JSX.Element { override decorate(): React.JSX.Element {
return ( return (
<ContextBlockComponent <ContextBlockComponent
nodeKey={this.getKey()} nodeKey={this.getKey()}
@@ -69,13 +69,13 @@ export class ContextBlockNode extends DecoratorNode<React.JSX.Element> {
return self.__canNotAddContext return self.__canNotAddContext
} }
static importJSON(serializedNode: SerializedNode): ContextBlockNode { static override importJSON(serializedNode: SerializedNode): ContextBlockNode {
const node = $createContextBlockNode(serializedNode.datasets, serializedNode.onAddContext, serializedNode.canNotAddContext) const node = $createContextBlockNode(serializedNode.datasets, serializedNode.onAddContext, serializedNode.canNotAddContext)
return node return node
} }
exportJSON(): SerializedNode { override exportJSON(): SerializedNode {
return { return {
type: 'context-block', type: 'context-block',
version: 1, version: 1,
@@ -85,7 +85,7 @@ export class ContextBlockNode extends DecoratorNode<React.JSX.Element> {
} }
} }
getTextContent(): string { override getTextContent(): string {
return '{{#context#}}' return '{{#context#}}'
} }
} }

View File

@@ -7,15 +7,15 @@ type SerializedNode = SerializedLexicalNode & { generatorType: GeneratorType }
export class CurrentBlockNode extends DecoratorNode<React.JSX.Element> { export class CurrentBlockNode extends DecoratorNode<React.JSX.Element> {
__generatorType: GeneratorType __generatorType: GeneratorType
static getType(): string { static override getType(): string {
return 'current-block' return 'current-block'
} }
static clone(node: CurrentBlockNode): CurrentBlockNode { static override clone(node: CurrentBlockNode): CurrentBlockNode {
return new CurrentBlockNode(node.__generatorType, node.getKey()) return new CurrentBlockNode(node.__generatorType, node.getKey())
} }
isInline(): boolean { override isInline(): boolean {
return true return true
} }
@@ -25,17 +25,17 @@ export class CurrentBlockNode extends DecoratorNode<React.JSX.Element> {
this.__generatorType = generatorType this.__generatorType = generatorType
} }
createDOM(): HTMLElement { override createDOM(): HTMLElement {
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('inline-flex', 'items-center', 'align-middle') div.classList.add('inline-flex', 'items-center', 'align-middle')
return div return div
} }
updateDOM(): false { override updateDOM(): false {
return false return false
} }
decorate(): React.JSX.Element { override decorate(): React.JSX.Element {
return ( return (
<CurrentBlockComponent <CurrentBlockComponent
nodeKey={this.getKey()} nodeKey={this.getKey()}
@@ -49,13 +49,13 @@ export class CurrentBlockNode extends DecoratorNode<React.JSX.Element> {
return self.__generatorType return self.__generatorType
} }
static importJSON(serializedNode: SerializedNode): CurrentBlockNode { static override importJSON(serializedNode: SerializedNode): CurrentBlockNode {
const node = $createCurrentBlockNode(serializedNode.generatorType) const node = $createCurrentBlockNode(serializedNode.generatorType)
return node return node
} }
exportJSON(): SerializedNode { override exportJSON(): SerializedNode {
return { return {
type: 'current-block', type: 'current-block',
version: 1, version: 1,
@@ -63,7 +63,7 @@ export class CurrentBlockNode extends DecoratorNode<React.JSX.Element> {
} }
} }
getTextContent(): string { override getTextContent(): string {
return '{{#current#}}' return '{{#current#}}'
} }
} }

View File

@@ -2,11 +2,11 @@ import type { EditorConfig, SerializedTextNode } from 'lexical'
import { $createTextNode, TextNode } from 'lexical' import { $createTextNode, TextNode } from 'lexical'
export class CustomTextNode extends TextNode { export class CustomTextNode extends TextNode {
static getType() { static override getType() {
return 'custom-text' return 'custom-text'
} }
static clone(node: CustomTextNode) { static override clone(node: CustomTextNode) {
return new CustomTextNode(node.__text, node.__key) return new CustomTextNode(node.__text, node.__key)
} }
@@ -14,12 +14,12 @@ export class CustomTextNode extends TextNode {
// super(text, key) // super(text, key)
// } // }
createDOM(config: EditorConfig) { override createDOM(config: EditorConfig) {
const dom = super.createDOM(config) const dom = super.createDOM(config)
return dom return dom
} }
static importJSON(serializedNode: SerializedTextNode): TextNode { static override importJSON(serializedNode: SerializedTextNode): TextNode {
const node = $createTextNode(serializedNode.text) const node = $createTextNode(serializedNode.text)
node.setFormat(serializedNode.format) node.setFormat(serializedNode.format)
node.setDetail(serializedNode.detail) node.setDetail(serializedNode.detail)
@@ -28,7 +28,7 @@ export class CustomTextNode extends TextNode {
return node return node
} }
exportJSON(): SerializedTextNode { override exportJSON(): SerializedTextNode {
return { return {
detail: this.getDetail(), detail: this.getDetail(),
format: this.getFormat(), format: this.getFormat(),
@@ -40,7 +40,7 @@ export class CustomTextNode extends TextNode {
} }
} }
isSimpleText() { override isSimpleText() {
return ( return (
(this.__type === 'text' || this.__type === 'custom-text') && this.__mode === 0) (this.__type === 'text' || this.__type === 'custom-text') && this.__mode === 0)
} }

View File

@@ -5,15 +5,15 @@ import ErrorMessageBlockComponent from './component'
type SerializedNode = SerializedLexicalNode type SerializedNode = SerializedLexicalNode
export class ErrorMessageBlockNode extends DecoratorNode<React.JSX.Element> { export class ErrorMessageBlockNode extends DecoratorNode<React.JSX.Element> {
static getType(): string { static override getType(): string {
return 'error-message-block' return 'error-message-block'
} }
static clone(node: ErrorMessageBlockNode): ErrorMessageBlockNode { static override clone(node: ErrorMessageBlockNode): ErrorMessageBlockNode {
return new ErrorMessageBlockNode(node.getKey()) return new ErrorMessageBlockNode(node.getKey())
} }
isInline(): boolean { override isInline(): boolean {
return true return true
} }
@@ -21,17 +21,17 @@ export class ErrorMessageBlockNode extends DecoratorNode<React.JSX.Element> {
super(key) super(key)
} }
createDOM(): HTMLElement { override createDOM(): HTMLElement {
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('inline-flex', 'items-center', 'align-middle') div.classList.add('inline-flex', 'items-center', 'align-middle')
return div return div
} }
updateDOM(): false { override updateDOM(): false {
return false return false
} }
decorate(): React.JSX.Element { override decorate(): React.JSX.Element {
return ( return (
<ErrorMessageBlockComponent <ErrorMessageBlockComponent
nodeKey={this.getKey()} nodeKey={this.getKey()}
@@ -39,20 +39,20 @@ export class ErrorMessageBlockNode extends DecoratorNode<React.JSX.Element> {
) )
} }
static importJSON(): ErrorMessageBlockNode { static override importJSON(): ErrorMessageBlockNode {
const node = $createErrorMessageBlockNode() const node = $createErrorMessageBlockNode()
return node return node
} }
exportJSON(): SerializedNode { override exportJSON(): SerializedNode {
return { return {
type: 'error-message-block', type: 'error-message-block',
version: 1, version: 1,
} }
} }
getTextContent(): string { override getTextContent(): string {
return '{{#error_message#}}' return '{{#error_message#}}'
} }
} }

View File

@@ -9,11 +9,11 @@ export class HistoryBlockNode extends DecoratorNode<React.JSX.Element> {
__roleName: RoleName __roleName: RoleName
__onEditRole: () => void __onEditRole: () => void
static getType(): string { static override getType(): string {
return 'history-block' return 'history-block'
} }
static clone(node: HistoryBlockNode): HistoryBlockNode { static override clone(node: HistoryBlockNode): HistoryBlockNode {
return new HistoryBlockNode(node.__roleName, node.__onEditRole, node.__key) return new HistoryBlockNode(node.__roleName, node.__onEditRole, node.__key)
} }
@@ -24,21 +24,21 @@ export class HistoryBlockNode extends DecoratorNode<React.JSX.Element> {
this.__onEditRole = onEditRole this.__onEditRole = onEditRole
} }
isInline(): boolean { override isInline(): boolean {
return true return true
} }
createDOM(): HTMLElement { override createDOM(): HTMLElement {
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('inline-flex', 'items-center', 'align-middle') div.classList.add('inline-flex', 'items-center', 'align-middle')
return div return div
} }
updateDOM(): false { override updateDOM(): false {
return false return false
} }
decorate(): React.JSX.Element { override decorate(): React.JSX.Element {
return ( return (
<HistoryBlockComponent <HistoryBlockComponent
nodeKey={this.getKey()} nodeKey={this.getKey()}
@@ -60,13 +60,13 @@ export class HistoryBlockNode extends DecoratorNode<React.JSX.Element> {
return self.__onEditRole return self.__onEditRole
} }
static importJSON(serializedNode: SerializedNode): HistoryBlockNode { static override importJSON(serializedNode: SerializedNode): HistoryBlockNode {
const node = $createHistoryBlockNode(serializedNode.roleName, serializedNode.onEditRole) const node = $createHistoryBlockNode(serializedNode.roleName, serializedNode.onEditRole)
return node return node
} }
exportJSON(): SerializedNode { override exportJSON(): SerializedNode {
return { return {
type: 'history-block', type: 'history-block',
version: 1, version: 1,
@@ -75,7 +75,7 @@ export class HistoryBlockNode extends DecoratorNode<React.JSX.Element> {
} }
} }
getTextContent(): string { override getTextContent(): string {
return '{{#histories#}}' return '{{#histories#}}'
} }
} }

View File

@@ -37,7 +37,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
__ragVariables?: Var[] __ragVariables?: Var[]
__readonly?: boolean __readonly?: boolean
isIsolated(): boolean { override isIsolated(): boolean {
return true // This is necessary for drag-and-drop to work correctly return true // This is necessary for drag-and-drop to work correctly
} }
@@ -45,7 +45,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
return true // This is necessary for drag-and-drop to work correctly return true // This is necessary for drag-and-drop to work correctly
} }
static getType(): string { static override getType(): string {
return 'hitl-input-block' return 'hitl-input-block'
} }
@@ -109,7 +109,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
return self.__readonly || false return self.__readonly || false
} }
static clone(node: HITLInputNode): HITLInputNode { static override clone(node: HITLInputNode): HITLInputNode {
return new HITLInputNode( return new HITLInputNode(
node.__variableName, node.__variableName,
node.__nodeId, node.__nodeId,
@@ -127,7 +127,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
) )
} }
isInline(): boolean { override isInline(): boolean {
return true return true
} }
@@ -162,17 +162,17 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
this.__readonly = readonly this.__readonly = readonly
} }
createDOM(): HTMLElement { override createDOM(): HTMLElement {
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('inline-flex', 'w-[calc(100%-1px)]', 'items-center', 'align-middle', 'support-drag') div.classList.add('inline-flex', 'w-[calc(100%-1px)]', 'items-center', 'align-middle', 'support-drag')
return div return div
} }
updateDOM(): false { override updateDOM(): false {
return false return false
} }
decorate(): React.JSX.Element { override decorate(): React.JSX.Element {
return ( return (
<HILTInputBlockComponent <HILTInputBlockComponent
nodeKey={this.getKey()} nodeKey={this.getKey()}
@@ -192,7 +192,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
) )
} }
static importJSON(serializedNode: SerializedNode): HITLInputNode { static override importJSON(serializedNode: SerializedNode): HITLInputNode {
const node = $createHITLInputNode( const node = $createHITLInputNode(
serializedNode.variableName, serializedNode.variableName,
serializedNode.nodeId, serializedNode.nodeId,
@@ -211,7 +211,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
return node return node
} }
exportJSON(): SerializedNode { override exportJSON(): SerializedNode {
return { return {
type: 'hitl-input-block', type: 'hitl-input-block',
version: 1, version: 1,
@@ -230,7 +230,7 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
} }
} }
getTextContent(): string { override getTextContent(): string {
return `{{#$output.${this.getVariableName()}#}}` return `{{#$output.${this.getVariableName()}#}}`
} }
} }

View File

@@ -5,15 +5,15 @@ import LastRunBlockComponent from './component'
type SerializedNode = SerializedLexicalNode type SerializedNode = SerializedLexicalNode
export class LastRunBlockNode extends DecoratorNode<React.JSX.Element> { export class LastRunBlockNode extends DecoratorNode<React.JSX.Element> {
static getType(): string { static override getType(): string {
return 'last-run-block' return 'last-run-block'
} }
static clone(node: LastRunBlockNode): LastRunBlockNode { static override clone(node: LastRunBlockNode): LastRunBlockNode {
return new LastRunBlockNode(node.getKey()) return new LastRunBlockNode(node.getKey())
} }
isInline(): boolean { override isInline(): boolean {
return true return true
} }
@@ -21,17 +21,17 @@ export class LastRunBlockNode extends DecoratorNode<React.JSX.Element> {
super(key) super(key)
} }
createDOM(): HTMLElement { override createDOM(): HTMLElement {
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('inline-flex', 'items-center', 'align-middle') div.classList.add('inline-flex', 'items-center', 'align-middle')
return div return div
} }
updateDOM(): false { override updateDOM(): false {
return false return false
} }
decorate(): React.JSX.Element { override decorate(): React.JSX.Element {
return ( return (
<LastRunBlockComponent <LastRunBlockComponent
nodeKey={this.getKey()} nodeKey={this.getKey()}
@@ -39,20 +39,20 @@ export class LastRunBlockNode extends DecoratorNode<React.JSX.Element> {
) )
} }
static importJSON(): LastRunBlockNode { static override importJSON(): LastRunBlockNode {
const node = $createLastRunBlockNode() const node = $createLastRunBlockNode()
return node return node
} }
exportJSON(): SerializedNode { override exportJSON(): SerializedNode {
return { return {
type: 'last-run-block', type: 'last-run-block',
version: 1, version: 1,
} }
} }
getTextContent(): string { override getTextContent(): string {
return '{{#last_run#}}' return '{{#last_run#}}'
} }
} }

View File

@@ -5,46 +5,46 @@ import QueryBlockComponent from './component'
type SerializedNode = SerializedLexicalNode type SerializedNode = SerializedLexicalNode
export class QueryBlockNode extends DecoratorNode<React.JSX.Element> { export class QueryBlockNode extends DecoratorNode<React.JSX.Element> {
static getType(): string { static override getType(): string {
return 'query-block' return 'query-block'
} }
static clone(): QueryBlockNode { static override clone(): QueryBlockNode {
return new QueryBlockNode() return new QueryBlockNode()
} }
isInline(): boolean { override isInline(): boolean {
return true return true
} }
createDOM(): HTMLElement { override createDOM(): HTMLElement {
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('inline-flex', 'items-center', 'align-middle') div.classList.add('inline-flex', 'items-center', 'align-middle')
return div return div
} }
updateDOM(): false { override updateDOM(): false {
return false return false
} }
decorate(): React.JSX.Element { override decorate(): React.JSX.Element {
return <QueryBlockComponent nodeKey={this.getKey()} /> return <QueryBlockComponent nodeKey={this.getKey()} />
} }
static importJSON(): QueryBlockNode { static override importJSON(): QueryBlockNode {
const node = $createQueryBlockNode() const node = $createQueryBlockNode()
return node return node
} }
exportJSON(): SerializedNode { override exportJSON(): SerializedNode {
return { return {
type: 'query-block', type: 'query-block',
version: 1, version: 1,
} }
} }
getTextContent(): string { override getTextContent(): string {
return '{{#query#}}' return '{{#query#}}'
} }
} }

View File

@@ -5,46 +5,46 @@ import RequestURLBlockComponent from './component'
type SerializedNode = SerializedLexicalNode type SerializedNode = SerializedLexicalNode
export class RequestURLBlockNode extends DecoratorNode<React.JSX.Element> { export class RequestURLBlockNode extends DecoratorNode<React.JSX.Element> {
static getType(): string { static override getType(): string {
return 'request-url-block' return 'request-url-block'
} }
static clone(node: RequestURLBlockNode): RequestURLBlockNode { static override clone(node: RequestURLBlockNode): RequestURLBlockNode {
return new RequestURLBlockNode(node.__key) return new RequestURLBlockNode(node.__key)
} }
isInline(): boolean { override isInline(): boolean {
return true return true
} }
createDOM(): HTMLElement { override createDOM(): HTMLElement {
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('inline-flex', 'items-center', 'align-middle') div.classList.add('inline-flex', 'items-center', 'align-middle')
return div return div
} }
updateDOM(): false { override updateDOM(): false {
return false return false
} }
decorate(): React.JSX.Element { override decorate(): React.JSX.Element {
return <RequestURLBlockComponent nodeKey={this.getKey()} /> return <RequestURLBlockComponent nodeKey={this.getKey()} />
} }
static importJSON(): RequestURLBlockNode { static override importJSON(): RequestURLBlockNode {
const node = $createRequestURLBlockNode() const node = $createRequestURLBlockNode()
return node return node
} }
exportJSON(): SerializedNode { override exportJSON(): SerializedNode {
return { return {
type: 'request-url-block', type: 'request-url-block',
version: 1, version: 1,
} }
} }
getTextContent(): string { override getTextContent(): string {
return '{{#url#}}' return '{{#url#}}'
} }
} }

View File

@@ -9,11 +9,11 @@ import {
} from 'lexical' } from 'lexical'
export class VariableValueBlockNode extends TextNode { export class VariableValueBlockNode extends TextNode {
static getType(): string { static override getType(): string {
return 'variable-value-block' return 'variable-value-block'
} }
static clone(node: VariableValueBlockNode): VariableValueBlockNode { static override clone(node: VariableValueBlockNode): VariableValueBlockNode {
return new VariableValueBlockNode(node.__text, node.__key) return new VariableValueBlockNode(node.__text, node.__key)
} }
@@ -21,13 +21,13 @@ export class VariableValueBlockNode extends TextNode {
// super(text, key) // super(text, key)
// } // }
createDOM(config: EditorConfig): HTMLElement { override createDOM(config: EditorConfig): HTMLElement {
const element = super.createDOM(config) const element = super.createDOM(config)
element.classList.add('inline-flex', 'items-center', 'px-0.5', 'h-[22px]', 'text-text-accent', 'rounded-[5px]', 'align-middle') element.classList.add('inline-flex', 'items-center', 'px-0.5', 'h-[22px]', 'text-text-accent', 'rounded-[5px]', 'align-middle')
return element return element
} }
static importJSON(serializedNode: SerializedTextNode): TextNode { static override importJSON(serializedNode: SerializedTextNode): TextNode {
const node = $createVariableValueBlockNode(serializedNode.text) const node = $createVariableValueBlockNode(serializedNode.text)
node.setFormat(serializedNode.format) node.setFormat(serializedNode.format)
node.setDetail(serializedNode.detail) node.setDetail(serializedNode.detail)
@@ -36,7 +36,7 @@ export class VariableValueBlockNode extends TextNode {
return node return node
} }
exportJSON(): SerializedTextNode { override exportJSON(): SerializedTextNode {
return { return {
detail: this.getDetail(), detail: this.getDetail(),
format: this.getFormat(), format: this.getFormat(),
@@ -48,7 +48,7 @@ export class VariableValueBlockNode extends TextNode {
} }
} }
canInsertTextBefore(): boolean { override canInsertTextBefore(): boolean {
return false return false
} }
} }

View File

@@ -19,11 +19,11 @@ export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element>
__getVarType?: GetVarType __getVarType?: GetVarType
__availableVariables?: NodeOutPutVar[] __availableVariables?: NodeOutPutVar[]
static getType(): string { static override getType(): string {
return 'workflow-variable-block' return 'workflow-variable-block'
} }
static clone(node: WorkflowVariableBlockNode): WorkflowVariableBlockNode { static override clone(node: WorkflowVariableBlockNode): WorkflowVariableBlockNode {
return new WorkflowVariableBlockNode( return new WorkflowVariableBlockNode(
node.__variables, node.__variables,
node.__workflowNodesMap, node.__workflowNodesMap,
@@ -33,7 +33,7 @@ export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element>
) )
} }
isInline(): boolean { override isInline(): boolean {
return true return true
} }
@@ -52,17 +52,17 @@ export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element>
this.__availableVariables = availableVariables this.__availableVariables = availableVariables
} }
createDOM(): HTMLElement { override createDOM(): HTMLElement {
const div = document.createElement('div') const div = document.createElement('div')
div.classList.add('inline-flex', 'items-center', 'align-middle') div.classList.add('inline-flex', 'items-center', 'align-middle')
return div return div
} }
updateDOM(): false { override updateDOM(): false {
return false return false
} }
decorate(): React.JSX.Element { override decorate(): React.JSX.Element {
return ( return (
<WorkflowVariableBlockComponent <WorkflowVariableBlockComponent
nodeKey={this.getKey()} nodeKey={this.getKey()}
@@ -74,7 +74,7 @@ export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element>
) )
} }
static importJSON(serializedNode: SerializedNode): WorkflowVariableBlockNode { static override importJSON(serializedNode: SerializedNode): WorkflowVariableBlockNode {
const node = $createWorkflowVariableBlockNode( const node = $createWorkflowVariableBlockNode(
serializedNode.variables, serializedNode.variables,
serializedNode.workflowNodesMap, serializedNode.workflowNodesMap,
@@ -85,7 +85,7 @@ export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element>
return node return node
} }
exportJSON(): SerializedNode { override exportJSON(): SerializedNode {
const json: SerializedNode = { const json: SerializedNode = {
type: 'workflow-variable-block', type: 'workflow-variable-block',
version: 1, version: 1,
@@ -119,7 +119,7 @@ export class WorkflowVariableBlockNode extends DecoratorNode<React.JSX.Element>
return self.__availableVariables return self.__availableVariables
} }
getTextContent(): string { override getTextContent(): string {
return `{{#${this.getVariables().join('.')}#}}` return `{{#${this.getVariables().join('.')}#}}`
} }
} }

View File

@@ -230,7 +230,7 @@ describe('UpdateDSLModal', () => {
it('should show an error when the selected file content is invalid for the current app mode', async () => { it('should show an error when the selected file content is invalid for the current app mode', async () => {
class InvalidDSLFileReader extends MockFileReader { class InvalidDSLFileReader extends MockFileReader {
readAsText(_file: Blob) { override readAsText(_file: Blob) {
const event = { target: { result: 'workflow:\n graph:\n nodes:\n - data:\n type: answer\n' } } as unknown as ProgressEvent<FileReader> const event = { target: { result: 'workflow:\n graph:\n nodes:\n - data:\n type: answer\n' } } as unknown as ProgressEvent<FileReader>
this.onload?.call(this as unknown as FileReader, event) this.onload?.call(this as unknown as FileReader, event)
} }

View File

@@ -55,7 +55,7 @@ const OutputVarList: FC<Props> = ({
replaceSpaceWithUnderscoreInVarNameInput(e.target) replaceSpaceWithUnderscoreInVarNameInput(e.target)
const newKey = e.target.value const newKey = e.target.value
validateVarInput(list.toSpliced(index, 1), newKey) validateVarInput(list.filter((_, itemIndex) => itemIndex !== index), newKey)
const newOutputs = produce(outputs, (draft) => { const newOutputs = produce(outputs, (draft) => {
draft[newKey] = draft[oldKey]! draft[newKey] = draft[oldKey]!

View File

@@ -67,7 +67,7 @@ const VarList: FC<Props> = ({
const newKey = e.target.value const newKey = e.target.value
validateVarInput(list.toSpliced(index, 1), newKey) validateVarInput(list.filter((_, itemIndex) => itemIndex !== index), newKey)
onVarNameChange?.(list[index]!.variable, newKey) onVarNameChange?.(list[index]!.variable, newKey)
const newList = produce(list, (draft) => { const newList = produce(list, (draft) => {

View File

@@ -1,6 +1,15 @@
import type { NodeTracing } from '@/types/workflow' import type { NodeTracing } from '@/types/workflow'
import { BlockEnum } from '@/app/components/workflow/types' import { BlockEnum } from '@/app/components/workflow/types'
function findLastIndex<T>(list: T[], predicate: (item: T) => boolean): number {
for (let index = list.length - 1; index >= 0; index--) {
if (predicate(list[index]!))
return index
}
return -1
}
function printNodeStructure(node: NodeTracing, depth: number) { function printNodeStructure(node: NodeTracing, depth: number) {
const indent = ' '.repeat(depth) const indent = ' '.repeat(depth)
console.log(`${indent}${node.title}`) console.log(`${indent}${node.title}`)
@@ -107,7 +116,7 @@ const format = (list: NodeTracing[], t: any, isPrint?: boolean): NodeTracing[] =
} }
} }
if (parentParallelStartNode!.parallelDetail.children) { if (parentParallelStartNode!.parallelDetail.children) {
const sameBranchNodesLastIndex = parentParallelStartNode.parallelDetail.children.findLastIndex((node) => { const sameBranchNodesLastIndex = findLastIndex(parentParallelStartNode.parallelDetail.children, (node) => {
const currStartNodeId = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null const currStartNodeId = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null
return currStartNodeId === parentParallelBranchStartNodeId return currStartNodeId === parentParallelBranchStartNodeId
}) })
@@ -124,7 +133,7 @@ const format = (list: NodeTracing[], t: any, isPrint?: boolean): NodeTracing[] =
const parallelStartNode = result.find(item => parallel_start_node_id === item.node_id) const parallelStartNode = result.find(item => parallel_start_node_id === item.node_id)
if (parallelStartNode && parallelStartNode.parallelDetail && parallelStartNode!.parallelDetail!.children) { if (parallelStartNode && parallelStartNode.parallelDetail && parallelStartNode!.parallelDetail!.children) {
const sameBranchNodesLastIndex = parallelStartNode.parallelDetail.children.findLastIndex((node) => { const sameBranchNodesLastIndex = findLastIndex(parallelStartNode.parallelDetail.children, (node) => {
const currStartNodeId = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null const currStartNodeId = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null
return currStartNodeId === branchStartNodeId return currStartNodeId === branchStartNodeId
}) })

View File

@@ -10,7 +10,7 @@ export const i18n = {
locales: LanguagesSupported, locales: LanguagesSupported,
} as const } as const
export { Locale } export type { Locale }
export const setLocaleOnClient = async (locale: Locale, reloadPage = true) => { export const setLocaleOnClient = async (locale: Locale, reloadPage = true) => {
Cookies.set(LOCALE_COOKIE_NAME, locale, { expires: 365 }) Cookies.set(LOCALE_COOKIE_NAME, locale, { expires: 365 })

View File

@@ -2,20 +2,6 @@ import { IS_DEV } from '@/config'
import { env } from '@/env' import { env } from '@/env'
async function main() { async function main() {
// Polyfill for Array.prototype.toSpliced (ES2023, Chrome 110+)
if (!Array.prototype.toSpliced) {
// eslint-disable-next-line no-extend-native
Array.prototype.toSpliced = function <T>(this: T[], start: number, deleteCount?: number, ...items: T[]): T[] {
const copy = this.slice()
// When deleteCount is undefined (omitted), delete to end; otherwise let splice handle coercion
if (deleteCount === undefined)
copy.splice(start, copy.length - start, ...items)
else
copy.splice(start, deleteCount, ...items)
return copy
}
}
if (!('localStorage' in globalThis) || !('sessionStorage' in globalThis)) { if (!('localStorage' in globalThis) || !('sessionStorage' in globalThis)) {
class StorageMock { class StorageMock {
data: Record<string, string> data: Record<string, string>

View File

@@ -48,8 +48,8 @@
"test": "vp test", "test": "vp test",
"test:coverage": "vp test --coverage", "test:coverage": "vp test --coverage",
"test:watch": "vp test --watch", "test:watch": "vp test --watch",
"type-check": "tsc --noEmit", "type-check": "tsc",
"type-check:tsgo": "tsgo --noEmit", "type-check:tsgo": "tsgo",
"uglify-embed": "node ./bin/uglify-embed" "uglify-embed": "node ./bin/uglify-embed"
}, },
"dependencies": { "dependencies": {
@@ -160,6 +160,7 @@
"@antfu/eslint-config": "catalog:", "@antfu/eslint-config": "catalog:",
"@chromatic-com/storybook": "catalog:", "@chromatic-com/storybook": "catalog:",
"@dify/iconify-collections": "workspace:*", "@dify/iconify-collections": "workspace:*",
"@dify/tsconfig": "workspace:*",
"@egoist/tailwindcss-icons": "catalog:", "@egoist/tailwindcss-icons": "catalog:",
"@eslint-react/eslint-plugin": "catalog:", "@eslint-react/eslint-plugin": "catalog:",
"@hono/node-server": "catalog:", "@hono/node-server": "catalog:",

View File

@@ -1,15 +1,7 @@
{ {
"extends": "@dify/tsconfig/nextjs.json",
"compilerOptions": { "compilerOptions": {
"incremental": true, "incremental": true,
"target": "es2022",
"jsx": "react-jsx",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"module": "esnext",
"moduleResolution": "bundler",
"paths": { "paths": {
"@/*": [ "@/*": [
"./*" "./*"
@@ -23,19 +15,7 @@
"vitest/globals", "vitest/globals",
"node" "node"
], ],
"allowJs": true, "allowJs": true
"strict": true,
"noUncheckedIndexedAccess": true,
"noEmit": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"skipLibCheck": true,
"plugins": [
{
"name": "next"
}
]
}, },
"include": [ "include": [
"next-env.d.ts", "next-env.d.ts",