Files
ComfyUI_frontend/scripts/diff-i18n.ts
Johnpaul Chiwetelu 90a701dd67 Road to No Explicit Any Part 11 (#8565)
## Summary

This PR removes `any` types from widgets, services, stores, and test
files, replacing them with proper TypeScript types.

### Key Changes

#### Type Safety Improvements
- Replaced `any` with `unknown`, explicit types, or proper interfaces
across widgets and services
- Added proper type imports (TgpuRoot, Point, StyleValue, etc.)
- Created typed interfaces (NumericWidgetOptions, TestWindow,
ImportFailureDetail, etc.)
- Fixed function return types to be non-nullable where appropriate
- Added type guards and null checks instead of non-null assertions
- Used `ComponentProps` from vue-component-type-helpers for component
testing

#### Widget System
- Added index signature to IWidgetOptions for Record compatibility
- Centralized disabled logic in WidgetInputNumberInput
- Moved template type assertions to computed properties
- Fixed ComboWidget getOptionLabel type assertions
- Improved remote widget type handling with runtime checks

#### Services & Stores
- Fixed getOrCreateViewer to return non-nullable values
- Updated addNodeOnGraph to use specific options type `{ pos?: Point }`
- Added proper type assertions for settings store retrieval
- Fixed executionIdToCurrentId return type (string | undefined)

#### Test Infrastructure
- Exported GraphOrSubgraph from litegraph barrel to avoid circular
dependencies
- Updated test fixtures with proper TypeScript types (TestInfo,
LGraphNode)
- Replaced loose Record types with ComponentProps in tests
- Added proper error handling in WebSocket fixture

#### Code Organization
- Created shared i18n-types module for locale data types
- Made ImportFailureDetail non-exported (internal use only)
- Added @public JSDoc tag to ElectronWindow type
- Fixed console.log usage in scripts to use allowed methods

### Files Changed

**Widgets & Components:**
-
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue
-
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue
-
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue
- src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue
-
src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
- src/lib/litegraph/src/widgets/ComboWidget.ts
- src/lib/litegraph/src/types/widgets.ts
- src/components/common/LazyImage.vue
- src/components/load3d/Load3dViewerContent.vue

**Services & Stores:**
- src/services/litegraphService.ts
- src/services/load3dService.ts
- src/services/colorPaletteService.ts
- src/stores/maskEditorStore.ts
- src/stores/nodeDefStore.ts
- src/platform/settings/settingStore.ts
- src/platform/workflow/management/stores/workflowStore.ts

**Composables & Utils:**
- src/composables/node/useWatchWidget.ts
- src/composables/useCanvasDrop.ts
- src/utils/widgetPropFilter.ts
- src/utils/queueDisplay.ts
- src/utils/envUtil.ts

**Test Files:**
- browser_tests/fixtures/ComfyPage.ts
- browser_tests/fixtures/ws.ts
- browser_tests/tests/actionbar.spec.ts
-
src/workbench/extensions/manager/components/manager/skeleton/PackCardGridSkeleton.test.ts
- src/lib/litegraph/src/subgraph/subgraphUtils.test.ts
- src/components/rightSidePanel/shared.test.ts
- src/platform/cloud/subscription/composables/useSubscription.test.ts
-
src/platform/workflow/persistence/composables/useWorkflowPersistence.test.ts

**Scripts & Types:**
- scripts/i18n-types.ts (new shared module)
- scripts/diff-i18n.ts
- scripts/check-unused-i18n-keys.ts
- src/workbench/extensions/manager/types/conflictDetectionTypes.ts
- src/types/algoliaTypes.ts
- src/types/simplifiedWidget.ts

**Infrastructure:**
- src/lib/litegraph/src/litegraph.ts (added GraphOrSubgraph export)
- src/lib/litegraph/src/infrastructure/CustomEventTarget.ts
- src/platform/assets/services/assetService.ts

**Stories:**
- apps/desktop-ui/src/views/InstallView.stories.ts
- src/components/queue/job/JobDetailsPopover.stories.ts

**Extension Manager:**
- src/workbench/extensions/manager/composables/useConflictDetection.ts
- src/workbench/extensions/manager/composables/useManagerQueue.ts
- src/workbench/extensions/manager/services/comfyManagerService.ts
- src/workbench/extensions/manager/utils/conflictMessageUtil.ts

### Testing

- [x] All TypeScript type checking passes (`pnpm typecheck`)
- [x] ESLint passes without errors (`pnpm lint`)
- [x] Format checks pass (`pnpm format:check`)
- [x] Knip (unused exports) passes (`pnpm knip`)
- [x] Pre-commit and pre-push hooks pass

Part of the "Road to No Explicit Any" initiative.

### Previous PRs in this series:
- Part 2: #7401
- Part 3: #7935
- Part 4: #7970
- Part 5: #8064
- Part 6: #8083
- Part 7: #8092
- Part 8 Group 1: #8253
- Part 8 Group 2: #8258
- Part 8 Group 3: #8304
- Part 8 Group 4: #8314
- Part 8 Group 5: #8329
- Part 8 Group 6: #8344
- Part 8 Group 7: #8459
- Part 8 Group 8: #8496
- Part 9: #8498
- Part 10: #8499

---------

Co-authored-by: Comfy Org PR Bot <snomiao+comfy-pr@gmail.com>
Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-02-05 16:29:28 -08:00

126 lines
3.2 KiB
TypeScript

import {
existsSync,
mkdirSync,
readFileSync,
readdirSync,
rmSync,
writeFileSync
} from 'fs'
import { dirname, join } from 'path'
import type { LocaleData } from './i18n-types'
// Ensure directories exist
function ensureDir(dir: string) {
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true })
}
}
// Read JSON file
function readJsonFile(path: string) {
try {
return JSON.parse(readFileSync(path, 'utf-8'))
} catch {
return {}
}
}
// Get all JSON files recursively
function getAllJsonFiles(dir: string): string[] {
const files: string[] = []
const items = readdirSync(dir, { withFileTypes: true })
for (const item of items) {
const path = join(dir, item.name)
if (item.isDirectory()) {
files.push(...getAllJsonFiles(path))
} else if (item.name.endsWith('.json')) {
files.push(path)
}
}
return files
}
// Find additions in new object compared to base
function findAdditions(base: LocaleData, updated: LocaleData): LocaleData {
const additions: LocaleData = {}
for (const key in updated) {
if (!(key in base)) {
additions[key] = updated[key]
} else if (
typeof updated[key] === 'object' &&
!Array.isArray(updated[key]) &&
typeof base[key] === 'object' &&
!Array.isArray(base[key])
) {
const nestedAdditions = findAdditions(base[key], updated[key])
if (Object.keys(nestedAdditions).length > 0) {
additions[key] = nestedAdditions
}
}
}
return additions
}
// Capture command
function capture(srcLocaleDir: string, tempBaseDir: string) {
ensureDir(tempBaseDir)
const files = getAllJsonFiles(srcLocaleDir)
for (const file of files) {
const relativePath = file.replace(srcLocaleDir, '')
const targetPath = join(tempBaseDir, relativePath)
ensureDir(dirname(targetPath))
writeFileSync(targetPath, readFileSync(file, 'utf8'))
}
console.warn('Captured current locale files to temp/base/')
}
// Diff command
function diff(srcLocaleDir: string, tempBaseDir: string, tempDiffDir: string) {
ensureDir(tempDiffDir)
const files = getAllJsonFiles(srcLocaleDir)
for (const file of files) {
const relativePath = file.replace(srcLocaleDir, '')
const basePath = join(tempBaseDir, relativePath)
const diffPath = join(tempDiffDir, relativePath)
const baseContent = readJsonFile(basePath)
const updatedContent = readJsonFile(file)
const additions = findAdditions(baseContent, updatedContent)
if (Object.keys(additions).length > 0) {
ensureDir(dirname(diffPath))
writeFileSync(diffPath, JSON.stringify(additions, null, 2))
console.warn(`Wrote diff to ${diffPath}`)
}
}
}
// Command handling
const command = process.argv[2]
const SRC_LOCALE_DIR = 'src/locales'
const TEMP_BASE_DIR = 'temp/base'
const TEMP_DIFF_DIR = 'temp/diff'
switch (command) {
case 'capture':
capture(SRC_LOCALE_DIR, TEMP_BASE_DIR)
break
case 'diff':
diff(SRC_LOCALE_DIR, TEMP_BASE_DIR, TEMP_DIFF_DIR)
break
case 'clean':
// Remove temp directory recursively
if (existsSync('temp')) {
rmSync('temp', { recursive: true, force: true })
console.warn('Removed temp directory')
}
break
default:
console.error('Please specify either "capture" or "diff" command')
}