feat(lint): enforce kebab-case filenames with ESLint (#4797)

Co-authored-by: 俊良 <[email protected]>
This commit is contained in:
Zqcand俊良 authored and GitHub committed 2026-06-22 10:10:07 +08:00
1 parent 02847d7245
commit 3d6b6f7475
5 files changed
+578 -1

No files matched your search

+1 -1
View File
@@ -120,7 +120,7 @@ npm run preflight # Full check: clean → install → format → lint → build
- **Tests**: Collocated with source (`file.test.ts` next to `file.ts`),
vitest framework
- **File naming**: `PascalCase.tsx` for React components, `kebab-case.ts` for
new non-component files. Leave existing `camelCase` files alone — renaming breaks `git blame` and imports.
`.ts` files in `packages/core` and `packages/cli` (enforced by ESLint). Existing camelCase files are allowlisted in `eslint.legacy-filenames.mjs`; rename opportunistically when touching them, updating all imports in the same commit (note: renames lose `git blame` history).
- **Comments**: Default to none. Add only when _why_ is non-obvious; don't delete existing ones as cleanup.
- **Commits**: Conventional Commits (e.g., `feat(cli): Add --json flag`)
- **Node.js**: Development and production both require `>=22` (Ink 7 + React 19.2 requirement)
+20
View File
@@ -14,6 +14,8 @@ import vitest from '@vitest/eslint-plugin';
import globals from 'globals';
// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format
import storybook from 'eslint-plugin-storybook';
import checkFile from 'eslint-plugin-check-file';
import { legacyFilenames } from './eslint.legacy-filenames.mjs';
export default tseslint.config(
{
@@ -166,6 +168,24 @@ export default tseslint.config(
'default-case': 'error',
},
},
{
// Enforce kebab-case filenames
files: ['packages/core/src/**/*.ts', 'packages/cli/src/**/*.ts'],
ignores: legacyFilenames.flatMap((name) => [
`**/${name}.ts`,
`**/${name}.*.ts`,
]),
plugins: {
'check-file': checkFile,
},
rules: {
'check-file/filename-naming-convention': [
'error',
{ '**/*.ts': 'KEBAB_CASE' },
{ ignoreMiddleExtensions: true },
],
},
},
{
files: ['packages/*/src/**/*.test.{ts,tsx}', 'packages/**/test/**/*.test.{ts,tsx}'],
plugins: {
+525
View File
@@ -0,0 +1,525 @@
/**
* Legacy non-kebab-case filenames in packages/core/src and packages/cli/src.
*
* Used by eslint.config.js to exclude these files from the kebab-case rule.
* Remove entries as files are renamed in migration PRs.
*
* See: https://github.com/QwenLM/qwen-code/issues/4419
*/
export const legacyFilenames = [
'abortController',
'aboutCommand',
'acpAgent',
'acpAgent.worktree',
'acpModelUtils',
'activeGoalStore',
'agentHistoryAdapter',
'agentsCommand',
'anthropicContentGenerator',
'apiPreconnect',
'approvalModeCommand',
'approvalModeDisplay',
'approvalModeVisuals',
'ArenaAgentClient',
'arenaCommand',
'arenaCommand.agentComplete',
'ArenaManager',
'argumentProcessor',
'AsciiArt',
'askUserQuestion',
'asyncHookRegistry',
'asyncMessageQueue',
'atCommandProcessor',
'atFileProcessor',
'atomicFileWrite',
'attributionTrailer',
'authCommand',
'authMethods',
'authPreflight',
'autoMode',
'availableModels',
'backgroundShellRegistry',
'backgroundWorkUtils',
'bareMode',
'baseController',
'BaseEmitter',
'BaseJsonOutputAdapter',
'baseLlmClient',
'branchCommand',
'btwCommand',
'bugCommand',
'BuiltinCommandLoader',
'BundledSkillLoader',
'bundlePaths',
'chatCompressionService',
'chatRecordingService',
'chatRecordingService.autoTitle',
'chatRecordingService.customTitle',
'clearCommand',
'clipboardUtils',
'commandMetadata',
'CommandService',
'commandUtils',
'commentJson',
'commitAttribution',
'compactionInputSlimming',
'compressCommand',
'computeStats',
'configResolver',
'contentGenerator',
'contextCommand',
'contextLengthError',
'ControlContext',
'ControlDispatcher',
'ControlService',
'copyCommand',
'coreToolScheduler',
'costCalculator',
'cpuProfiler',
'crawlCache',
'cronDisplay',
'cronParser',
'cronScheduler',
'customBanner',
'customMatchers',
'daemonStatusProvider',
'DaemonTuiAdapter',
'dangerousRules',
'DataProcessor',
'debugLogger',
'debugMode',
'deepMerge',
'deleteCommand',
'denialTracking',
'detectTodoChanges',
'deviceFlow',
'dialogScopeUtils',
'diffCommand',
'diffOptions',
'displayUtils',
'docsCommand',
'doctorChecks',
'doctorCommand',
'dreamAgentPlanner',
'dreamCommand',
'DualOutputBridge',
'earlyInputCapture',
'editHelper',
'editorCommand',
'editorSettingsManager',
'envInterpolator',
'environmentContext',
'envSnapshot',
'envVarResolver',
'errorCodes',
'errorHandler',
'errorParsing',
'errorReporting',
'eventBus',
'exitPlanMode',
'exportCommand',
'extensionManager',
'extensionsCommand',
'extensionSettings',
'extractAgent',
'extractionAgentPlanner',
'extractionPlanner',
'FileCommandLoader',
'FileCommandLoader-extension',
'FileCommandLoader-markdown',
'fileDiscoveryService',
'fileHistoryService',
'fileReadCache',
'fileSearch',
'fileSystemService',
'fileUtils',
'followupState',
'forgetCommand',
'forkedAgent',
'forkedAgent.agent',
'forkedAgent.cache',
'functionHookRunner',
'geminiChat',
'geminiContentGenerator',
'geminiRequest',
'generateContentResponseUtilities',
'generatedFiles',
'getFolderStructure',
'getPty',
'gitDiff',
'gitIgnoreParser',
'gitInit',
'gitService',
'gitUtils',
'gitWorktreeService',
'gitWorktreeService.hooks.integ',
'gitWorktreeService.symlinks.integ',
'goalCommand',
'goalHook',
'goalJudge',
'goalLoop',
'gradientUtils',
'handleAutoUpdate',
'headlessSafetyWarnings',
'helpCommand',
'historyMapping',
'HistoryReplayer',
'historyUtils',
'hookAggregator',
'hookController',
'hookEventHandler',
'hookPlanner',
'hookRegistry',
'hookRunner',
'hooksCommand',
'hookSystem',
'httpAcpBridge',
'httpHookRunner',
'iconvHelper',
'ideCommand',
'ideContext',
'ignorePatterns',
'imageTokenizer',
'initCommand',
'injectionParser',
'inMemoryChannel',
'InProcessBackend',
'insightCommand',
'insightProtocol',
'installationInfo',
'installationManager',
'internalPromptIds',
'isNarrowWidth',
'ITermBackend',
'JsonOutputAdapter',
'jsonSchemaArg',
'keyBindings',
'keyMatchers',
'keyToAnsi',
'kittyProtocolDetector',
'languageCommand',
'languageUtils',
'lastInteractionAt',
'latexRenderer',
'layoutUtils',
'LlmRewriter',
'loadedSettingsAdapter',
'loggingContentGenerator',
'loopbackBinds',
'loopDetectionService',
'lowlightLoader',
'LruCache',
'lspCommand',
'LspConfigLoader',
'LspConnectionFactory',
'LspResponseNormalizer',
'LspServerManager',
'markdownUtilities',
'matcherGrouping',
'mcpCommand',
'McpPromptLoader',
'memoryAge',
'memoryCommand',
'memoryDiagnostics',
'memoryDiagnosticsDumper',
'memoryDiscovery',
'memoryImportProcessor',
'memoryLifecycle',
'memoryPressureMonitor',
'mergeCompactToolGroups',
'mermaidImageRenderer',
'mermaidVisualRenderer',
'MessageEmitter',
'messageInspectors',
'MessageRewriteMiddleware',
'mockCommandContext',
'mockWorkspaceContext',
'modalityDefaults',
'modelCommand',
'modelConfigErrors',
'modelConfigResolver',
'modelConfigUtils',
'modelId',
'modelProvidersScope',
'modelRegistry',
'modelsBySource',
'modelsConfig',
'monitorRegistry',
'mustTranslateKeys',
'NativeLspClient',
'NativeLspService',
'nextSpeakerChecker',
'nonInteractiveCli',
'nonInteractiveCliCommands',
'nonInteractiveHelpers',
'nonInteractiveToolExecutor',
'nonInteractiveUi',
'notificationService',
'openaiContentGenerator',
'openaiLogger',
'openaiTimeoutHandling',
'orphanedToolCallsTest',
'overlayFs',
'partUtils',
'pathReader',
'permissionController',
'permissionFlow',
'permissionsCommand',
'permissionUtils',
'planCommand',
'PlanEmitter',
'platformConstants',
'postCompactAttachments',
'priorReadEnforcement',
'processUtils',
'projectPath',
'projectRoot',
'projectSummary',
'promptHookIntegration',
'promptHookRunner',
'promptIdContext',
'proxyUtils',
'QualitativeInsightTypes',
'quitCommand',
'quotaErrorDetection',
'qwenContentGenerator',
'qwenDeviceFlowProvider',
'qwenIgnoreParser',
'qwenOAuth2',
'rateLimit',
'readManyFiles',
'readStdin',
'recapCommand',
'registerSkillHooks',
'relevanceSelector',
'rememberCommand',
'RemoteInputWatcher',
'renameCommand',
'requestCaptureContext',
'requestTokenizer',
'resolvePath',
'responseParsingOptions',
'restoreCommand',
'restoreGoal',
'resumeCommand',
'resumeHistoryUtils',
'retryContext',
'rewindCommand',
'ripGrep',
'ripgrepUtils',
'rulesDiscovery',
'runBudget',
'runQwenServe',
'runtimeDiagnostics',
'runtimeFetchOptions',
'runtimeOutputDirContext',
'runtimeStatus',
'runtimeStatus.config',
'safeJsonParse',
'safeJsonStringify',
'sandboxConfig',
'schemaConverter',
'schemaValidator',
'sdkMcpController',
'serviceAPIs',
'Session',
'Session.worktree',
'sessionHooksManager',
'sessionPaths',
'sessionPickerUtils',
'sessionRecap',
'sessionService',
'sessionService.corruption',
'sessionService.rename',
'sessionStorageUtils',
'sessionTitle',
'settingsCommand',
'settingsSchema',
'settingsUtils',
'setupGithubCommand',
'sharedTokenManager',
'shellAstParser',
'shellCommandProcessor',
'shellContextEnv',
'shellExecutionService',
'shellProcessor',
'shellReadOnlyChecker',
'sideQuery',
'SkillCommandLoader',
'skillReviewAgentPlanner',
'skillReviewNudge',
'skillsCommand',
'slashCommandProcessor',
'sourceLabels',
'spawnWrapper',
'speculationToolGate',
'ssrfGuard',
'startupEventSink',
'startupProfiler',
'startupWarnings',
'StaticInsightGenerator',
'StaticInsightTypes',
'statsCommand',
'statuslineCommand',
'statusLinePresets',
'stdioHelpers',
'stopHookCap',
'streamContentDetection',
'streamingToolCallParser',
'StreamJsonInputReader',
'StreamJsonOutputAdapter',
'StreamJsonOutputAdapter.dualOutput',
'subagentGenerator',
'subagentNameContext',
'SubAgentTracker',
'suggestionGenerator',
'summaryCommand',
'supportedImageFormats',
'symlinkScope',
'synchronizedOutput',
'syntheticOutput',
'systemController',
'systemEncoding',
'systemInfo',
'systemInfoFields',
'taggedThinkingParser',
'tasksCommand',
'TemplateRenderer',
'terminalRedrawOptimizer',
'terminalSafe',
'terminalSerializer',
'terminalSetup',
'terminalSetupCommand',
'testUtils',
'textConstants',
'textTokenizer',
'textUtils',
'themeCommand',
'thoughtUtils',
'throttledOnce',
'tipHistory',
'tipRegistry',
'Tips',
'tipScheduler',
'TmuxBackend',
'toAutoClassifierInput',
'todoSnapshot',
'todoWrite',
'tokenEstimation',
'tokenLimits',
'ToolCallEmitter',
'toolHookTriggers',
'toolsCommand',
'toolUseSummary',
'translationDict',
'truncatedDiffPreview',
'trustCommand',
'trustedFolders',
'trustedHooks',
'TurnBuffer',
'uiTelemetry',
'updateCheck',
'updateEventEmitter',
'urlValidator',
'useAgentsManagerDialog',
'useAgentStreamingState',
'useAnimatedScrollbar',
'useAnimationFrame',
'useApprovalModeCommand',
'useArenaCommand',
'useArenaInProcess',
'useAtCompletion',
'useAttentionNotifications',
'useAuth',
'useAutoAcceptIndicator',
'useAwaySummary',
'useBackgroundTaskView',
'useBatchedScroll',
'useBracketedPaste',
'useBranchCommand',
'useCommandCompletion',
'useCommandMigration',
'useCompletion',
'useConfigInitMessage',
'useContextualTips',
'useDeleteCommand',
'useDialogClose',
'useDiffData',
'useDoublePress',
'useEditorSettings',
'useExportCompletion',
'useExtensionsManagerDialog',
'useExtensionUpdates',
'useFeedbackDialog',
'useFocus',
'useFolderTrust',
'useGeminiStream',
'useGitBranchName',
'useHistoryManager',
'useHooksDialog',
'useIdeTrustListener',
'useInitializationAuthError',
'useInputHistory',
'useInputHistoryStore',
'useKeypress',
'useKittyKeyboardProtocol',
'useLaunchEditor',
'useLoadingIndicator',
'useLogger',
'useMcpDialog',
'useMCPHealth',
'useMemoryDialog',
'useMemoryMonitor',
'useMessageQueue',
'useModelCommand',
'useMouseEvents',
'usePhraseCycler',
'usePreferredEditor',
'useProviderSetupFlow',
'useProviderUpdates',
'useQwenAuth',
'useReactToolScheduler',
'useRefreshMemoryCommand',
'useResumeCommand',
'userPromptExpansionHook',
'userStartupWarnings',
'useSelectionList',
'useSessionPicker',
'useSessionSearchInput',
'useSettingsCommand',
'useShellHistory',
'useShowMemoryCommand',
'useSkillsManagerDialog',
'useSlashCompletion',
'useStateAndRef',
'useStatusLine',
'useSubagentCreateDialog',
'useTerminalNotification',
'useTerminalProgress',
'useTerminalSize',
'useThemeCommand',
'useTimer',
'useTomlMigration',
'useToolScheduler',
'useTrustModify',
'useTurnDiffs',
'useWelcomeBack',
'useWorktreeSession',
'validateNonInterActiveAuth',
'variableSchema',
'vimCommand',
'warningHandler',
'windowsPath',
'windowTitle',
'workspaceAgents',
'workspaceContext',
'workspaceFileRead',
'workspaceFileSystem',
'workspaceFileWrite',
'workspaceMemory',
'worktreeCleanup',
'worktreeSessionService',
'worktreeStartup',
'writeContextFile',
'writeWithBackup',
];
+31
View File
@@ -44,6 +44,7 @@
"esbuild-plugin-wasm": "^1.1.0",
"eslint": "^9.24.0",
"eslint-config-prettier": "^10.1.2",
"eslint-plugin-check-file": "^3.3.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-license-header": "^0.8.0",
"eslint-plugin-react": "^7.37.5",
@@ -10345,6 +10346,36 @@
"ms": "^2.1.1"
}
},
"node_modules/eslint-plugin-check-file": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-check-file/-/eslint-plugin-check-file-3.3.1.tgz",
"integrity": "sha512-b7fDkp8Y0T9vloTYSrkMnb5Cqpk1bc6+jDQdgKIhzdwb47NmLAvMFYo3SzHOPF8u4SEsOVhmrNSbo6Sp633syg==",
"dev": true,
"funding": [
{
"type": "ko_fi",
"url": "https://ko-fi.com/huanluo"
},
{
"type": "github",
"url": "https://github.com/sponsors/dukeluo"
}
],
"license": "Apache-2.0",
"workspaces": [
"examples/basic"
],
"dependencies": {
"is-glob": "^4.0.3",
"micromatch": "^4.0.8"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"eslint": ">=9.0.0"
}
},
"node_modules/eslint-plugin-import": {
"version": "2.32.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
+1
View File
@@ -121,6 +121,7 @@
"esbuild-plugin-wasm": "^1.1.0",
"eslint": "^9.24.0",
"eslint-config-prettier": "^10.1.2",
"eslint-plugin-check-file": "^3.3.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-license-header": "^0.8.0",
"eslint-plugin-react": "^7.37.5",