mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-01 17:59:09 +08:00
feat(preferences): auto-generate preferences configuration from classification.json
This commit introduces an auto-generated preferences configuration file, replacing the previous manual definitions. The new structure is based on the latest classification.json and includes comprehensive settings for various application features. The auto-generation process ensures that the preferences are up-to-date and consistent with the defined classifications.
This commit is contained in:
parent
21e40db086
commit
4e3f8a8f76
@ -1,35 +1,510 @@
|
|||||||
/**
|
/**
|
||||||
* we should use sorted object keys
|
* Auto-generated preferences configuration
|
||||||
* use `eslint --fix` to auto sort keys
|
* Generated at: 2025-08-09T07:25:38.982Z
|
||||||
|
*
|
||||||
|
* This file is automatically generated from classification.json
|
||||||
|
* To update this file, modify classification.json and run:
|
||||||
|
* node .claude/data-classify/scripts/generate-preferences.js
|
||||||
|
*
|
||||||
|
* === AUTO-GENERATED CONTENT START ===
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* eslint @typescript-eslint/member-ordering: ["error", {
|
/* eslint @typescript-eslint/member-ordering: ["error", {
|
||||||
"interfaces": { "order": "alphabetically" },
|
"interfaces": { "order": "alphabetically" },
|
||||||
"typeLiterals": { "order": "alphabetically" }
|
"typeLiterals": { "order": "alphabetically" }
|
||||||
}] */
|
}] */
|
||||||
|
|
||||||
export interface PreferencesType {
|
export interface PreferencesType {
|
||||||
default: {
|
default: {
|
||||||
'app.test5': {
|
// redux/settings/enableDeveloperMode
|
||||||
content1: string
|
'app.developer_mode.enabled': boolean
|
||||||
content2: number
|
// redux/settings/disableHardwareAcceleration
|
||||||
}
|
'app.disable_hardware_acceleration': boolean
|
||||||
'sys.a.test3': boolean
|
// redux/settings/autoCheckUpdate
|
||||||
'sys.a.test4': string[]
|
'app.dist.auto_update.enabled': boolean
|
||||||
'ui.a.test1': string
|
// redux/settings/testChannel
|
||||||
'ui.b.test2': number
|
'app.dist.test_plan.channel': string
|
||||||
|
// redux/settings/testPlan
|
||||||
|
'app.dist.test_plan.enabled': boolean
|
||||||
|
// electronStore/Language/Language
|
||||||
|
'app.language': unknown | null
|
||||||
|
// redux/settings/launchOnBoot
|
||||||
|
'app.launch_on_boot': boolean
|
||||||
|
// redux/settings/notification.assistant
|
||||||
|
'app.notification.assistant.enabled': boolean
|
||||||
|
// redux/settings/notification.backup
|
||||||
|
'app.notification.backup.enabled': boolean
|
||||||
|
// redux/settings/notification.knowledge
|
||||||
|
'app.notification.knowledge.enabled': boolean
|
||||||
|
// redux/settings/enableDataCollection
|
||||||
|
'app.privacy.data_collection.enabled': boolean
|
||||||
|
// redux/settings/proxyBypassRules
|
||||||
|
'app.proxy.bypass_rules': string | null
|
||||||
|
// redux/settings/proxyMode
|
||||||
|
'app.proxy.mode': string
|
||||||
|
// redux/settings/proxyUrl
|
||||||
|
'app.proxy.url': string | null
|
||||||
|
// redux/settings/enableSpellCheck
|
||||||
|
'app.spell_check.enabled': boolean
|
||||||
|
// redux/settings/spellCheckLanguages
|
||||||
|
'app.spell_check.languages': unknown[]
|
||||||
|
// redux/settings/theme
|
||||||
|
'app.theme.mode': string
|
||||||
|
// redux/settings/userTheme
|
||||||
|
'app.theme.user_defined': Record<string, unknown>
|
||||||
|
// redux/settings/windowStyle
|
||||||
|
'app.theme.window_style': string
|
||||||
|
// redux/settings/tray
|
||||||
|
'app.tray.enabled': boolean
|
||||||
|
// redux/settings/trayOnClose
|
||||||
|
'app.tray.on_close': boolean
|
||||||
|
// redux/settings/launchToTray
|
||||||
|
'app.tray.on_launch': boolean
|
||||||
|
// redux/settings/userId
|
||||||
|
'app.user.id': string
|
||||||
|
// redux/settings/userName
|
||||||
|
'app.user.name': string
|
||||||
|
// electronStore/ZoomFactor/ZoomFactor
|
||||||
|
'app.zoom_factor': unknown | null
|
||||||
|
// redux/settings/codeCollapsible
|
||||||
|
'chat.code.collapsible': boolean
|
||||||
|
// redux/settings/codeEditor.autocompletion
|
||||||
|
'chat.code.editor.autocompletion': boolean
|
||||||
|
// redux/settings/codeEditor.foldGutter
|
||||||
|
'chat.code.editor.fold_gutter': boolean
|
||||||
|
// redux/settings/codeEditor.enabled
|
||||||
|
'chat.code.editor.highlight_active_line': boolean
|
||||||
|
// redux/settings/codeEditor.keymap
|
||||||
|
'chat.code.editor.keymap': boolean
|
||||||
|
// redux/settings/codeEditor.themeDark
|
||||||
|
'chat.code.editor.theme_dark': string
|
||||||
|
// redux/settings/codeEditor.themeLight
|
||||||
|
'chat.code.editor.theme_light': string
|
||||||
|
// redux/settings/codeExecution.enabled
|
||||||
|
'chat.code.execution.enabled': boolean
|
||||||
|
// redux/settings/codeExecution.timeoutMinutes
|
||||||
|
'chat.code.execution.timeout_minutes': number
|
||||||
|
// redux/settings/codeImageTools
|
||||||
|
'chat.code.image_tools': boolean
|
||||||
|
// redux/settings/codePreview.themeDark
|
||||||
|
'chat.code.preview.theme_dark': string
|
||||||
|
// redux/settings/codePreview.themeLight
|
||||||
|
'chat.code.preview.theme_light': string
|
||||||
|
// redux/settings/codeShowLineNumbers
|
||||||
|
'chat.code.show_line_numbers': boolean
|
||||||
|
// redux/settings/codeViewer.themeDark
|
||||||
|
'chat.code.viewer.theme_dark': string
|
||||||
|
// redux/settings/codeViewer.themeLight
|
||||||
|
'chat.code.viewer.theme_light': string
|
||||||
|
// redux/settings/codeWrappable
|
||||||
|
'chat.code.wrappable': boolean
|
||||||
|
// redux/settings/enableBackspaceDeleteModel
|
||||||
|
'chat.input.backspace_delete_model': boolean
|
||||||
|
// redux/settings/pasteLongTextAsFile
|
||||||
|
'chat.input.paste_long_text_as_file': boolean
|
||||||
|
// redux/settings/pasteLongTextThreshold
|
||||||
|
'chat.input.paste_long_text_threshold': number
|
||||||
|
// redux/settings/enableQuickPanelTriggers
|
||||||
|
'chat.input.quick_panel.triggers_enabled': boolean
|
||||||
|
// redux/settings/sendMessageShortcut
|
||||||
|
'chat.input.send_message_shortcut': string
|
||||||
|
// redux/settings/showInputEstimatedTokens
|
||||||
|
'chat.input.show_estimated_tokens': boolean
|
||||||
|
// redux/settings/autoTranslateWithSpace
|
||||||
|
'chat.input.translate.auto_translate_with_space': boolean
|
||||||
|
// redux/settings/showTranslateConfirm
|
||||||
|
'chat.input.translate.show_confirm': boolean
|
||||||
|
// redux/settings/messageFont
|
||||||
|
'chat.message.font': string
|
||||||
|
// redux/settings/fontSize
|
||||||
|
'chat.message.font_size': number
|
||||||
|
// redux/settings/mathEngine
|
||||||
|
'chat.message.math_engine': string
|
||||||
|
// redux/settings/foldDisplayMode
|
||||||
|
'chat.message.multi_model.fold_display_mode': string
|
||||||
|
// redux/settings/gridColumns
|
||||||
|
'chat.message.multi_model.grid_columns': number
|
||||||
|
// redux/settings/gridPopoverTrigger
|
||||||
|
'chat.message.multi_model.grid_popover_trigger': string
|
||||||
|
// redux/settings/multiModelMessageStyle
|
||||||
|
'chat.message.multi_model.style': string
|
||||||
|
// redux/settings/messageNavigation
|
||||||
|
'chat.message.navigation_mode': string
|
||||||
|
// redux/settings/showMessageDivider
|
||||||
|
'chat.message.show_divider': boolean
|
||||||
|
// redux/settings/showPrompt
|
||||||
|
'chat.message.show_prompt': boolean
|
||||||
|
// redux/settings/showTokens
|
||||||
|
'chat.message.show_tokens': boolean
|
||||||
|
// redux/settings/messageStyle
|
||||||
|
'chat.message.style': string
|
||||||
|
// redux/settings/thoughtAutoCollapse
|
||||||
|
'chat.message.thought.auto_collapse': boolean
|
||||||
|
// redux/settings/narrowMode
|
||||||
|
'chat.narrow_mode': boolean
|
||||||
|
// redux/settings/skipBackupFile
|
||||||
|
'data.backup.general.skip_backup_file': boolean
|
||||||
|
// redux/settings/localBackupAutoSync
|
||||||
|
'data.backup.local.auto_sync': boolean
|
||||||
|
// redux/settings/localBackupDir
|
||||||
|
'data.backup.local.dir': string
|
||||||
|
// redux/settings/localBackupMaxBackups
|
||||||
|
'data.backup.local.max_backups': number
|
||||||
|
// redux/settings/localBackupSkipBackupFile
|
||||||
|
'data.backup.local.skip_backup_file': boolean
|
||||||
|
// redux/settings/localBackupSyncInterval
|
||||||
|
'data.backup.local.sync_interval': number
|
||||||
|
// redux/nutstore/nutstoreAutoSync
|
||||||
|
'data.backup.nutstore.auto_sync': boolean | null
|
||||||
|
// redux/nutstore/nutstorePath
|
||||||
|
'data.backup.nutstore.path': string | null
|
||||||
|
// redux/nutstore/nutstoreSkipBackupFile
|
||||||
|
'data.backup.nutstore.skip_backup_file': boolean | null
|
||||||
|
// redux/nutstore/nutstoreSyncInterval
|
||||||
|
'data.backup.nutstore.sync_interval': number | null
|
||||||
|
// redux/nutstore/nutstoreSyncState
|
||||||
|
'data.backup.nutstore.sync_state': Record<string, unknown> | null
|
||||||
|
// redux/nutstore/nutstoreToken
|
||||||
|
'data.backup.nutstore.token': string | null
|
||||||
|
// redux/settings/s3.accessKeyId
|
||||||
|
'data.backup.s3.access_key_id': string
|
||||||
|
// redux/settings/s3.autoSync
|
||||||
|
'data.backup.s3.auto_sync': boolean
|
||||||
|
// redux/settings/s3.bucket
|
||||||
|
'data.backup.s3.bucket': string
|
||||||
|
// redux/settings/s3.endpoint
|
||||||
|
'data.backup.s3.endpoint': string
|
||||||
|
// redux/settings/s3.maxBackups
|
||||||
|
'data.backup.s3.max_backups': number
|
||||||
|
// redux/settings/s3.region
|
||||||
|
'data.backup.s3.region': string
|
||||||
|
// redux/settings/s3.root
|
||||||
|
'data.backup.s3.root': string
|
||||||
|
// redux/settings/s3.secretAccessKey
|
||||||
|
'data.backup.s3.secret_access_key': string
|
||||||
|
// redux/settings/s3.skipBackupFile
|
||||||
|
'data.backup.s3.skip_backup_file': boolean
|
||||||
|
// redux/settings/s3.syncInterval
|
||||||
|
'data.backup.s3.sync_interval': number
|
||||||
|
// redux/settings/webdavAutoSync
|
||||||
|
'data.backup.webdav.auto_sync': boolean
|
||||||
|
// redux/settings/webdavDisableStream
|
||||||
|
'data.backup.webdav.disable_stream': boolean
|
||||||
|
// redux/settings/webdavHost
|
||||||
|
'data.backup.webdav.host': string
|
||||||
|
// redux/settings/webdavMaxBackups
|
||||||
|
'data.backup.webdav.max_backups': number
|
||||||
|
// redux/settings/webdavPass
|
||||||
|
'data.backup.webdav.pass': string
|
||||||
|
// redux/settings/webdavPath
|
||||||
|
'data.backup.webdav.path': string
|
||||||
|
// redux/settings/webdavSkipBackupFile
|
||||||
|
'data.backup.webdav.skip_backup_file': boolean
|
||||||
|
// redux/settings/webdavSyncInterval
|
||||||
|
'data.backup.webdav.sync_interval': number
|
||||||
|
// redux/settings/webdavUser
|
||||||
|
'data.backup.webdav.user': string
|
||||||
|
// redux/settings/excludeCitationsInExport
|
||||||
|
'data.export.markdown.exclude_citations': boolean
|
||||||
|
// redux/settings/forceDollarMathInMarkdown
|
||||||
|
'data.export.markdown.force_dollar_math': boolean
|
||||||
|
// redux/settings/markdownExportPath
|
||||||
|
'data.export.markdown.path': string | null
|
||||||
|
// redux/settings/showModelNameInMarkdown
|
||||||
|
'data.export.markdown.show_model_name': boolean
|
||||||
|
// redux/settings/showModelProviderInMarkdown
|
||||||
|
'data.export.markdown.show_model_provider': boolean
|
||||||
|
// redux/settings/standardizeCitationsInExport
|
||||||
|
'data.export.markdown.standardize_citations': boolean
|
||||||
|
// redux/settings/useTopicNamingForMessageTitle
|
||||||
|
'data.export.markdown.use_topic_naming_for_message_title': boolean
|
||||||
|
// redux/settings/exportMenuOptions.docx
|
||||||
|
'data.export.menus.docx': boolean
|
||||||
|
// redux/settings/exportMenuOptions.image
|
||||||
|
'data.export.menus.image': boolean
|
||||||
|
// redux/settings/exportMenuOptions.joplin
|
||||||
|
'data.export.menus.joplin': boolean
|
||||||
|
// redux/settings/exportMenuOptions.markdown
|
||||||
|
'data.export.menus.markdown': boolean
|
||||||
|
// redux/settings/exportMenuOptions.markdown_reason
|
||||||
|
'data.export.menus.markdown_reason': boolean
|
||||||
|
// redux/settings/exportMenuOptions.notion
|
||||||
|
'data.export.menus.notion': boolean
|
||||||
|
// redux/settings/exportMenuOptions.obsidian
|
||||||
|
'data.export.menus.obsidian': boolean
|
||||||
|
// redux/settings/exportMenuOptions.plain_text
|
||||||
|
'data.export.menus.plain_text': boolean
|
||||||
|
// redux/settings/exportMenuOptions.siyuan
|
||||||
|
'data.export.menus.siyuan': boolean
|
||||||
|
// redux/settings/exportMenuOptions.yuque
|
||||||
|
'data.export.menus.yuque': boolean
|
||||||
|
// redux/settings/joplinExportReasoning
|
||||||
|
'data.integration.joplin.export_reasoning': boolean
|
||||||
|
// redux/settings/joplinToken
|
||||||
|
'data.integration.joplin.token': string
|
||||||
|
// redux/settings/joplinUrl
|
||||||
|
'data.integration.joplin.url': string
|
||||||
|
// redux/settings/notionApiKey
|
||||||
|
'data.integration.notion.api_key': string
|
||||||
|
// redux/settings/notionDatabaseID
|
||||||
|
'data.integration.notion.database_id': string
|
||||||
|
// redux/settings/notionExportReasoning
|
||||||
|
'data.integration.notion.export_reasoning': boolean
|
||||||
|
// redux/settings/notionPageNameKey
|
||||||
|
'data.integration.notion.page_name_key': string
|
||||||
|
// redux/settings/defaultObsidianVault
|
||||||
|
'data.integration.obsidian.default_vault': string | null
|
||||||
|
// redux/settings/siyuanApiUrl
|
||||||
|
'data.integration.siyuan.api_url': string | null
|
||||||
|
// redux/settings/siyuanBoxId
|
||||||
|
'data.integration.siyuan.box_id': string | null
|
||||||
|
// redux/settings/siyuanRootPath
|
||||||
|
'data.integration.siyuan.root_path': string | null
|
||||||
|
// redux/settings/siyuanToken
|
||||||
|
'data.integration.siyuan.token': string | null
|
||||||
|
// redux/settings/yuqueRepoId
|
||||||
|
'data.integration.yuque.repo_id': string
|
||||||
|
// redux/settings/yuqueToken
|
||||||
|
'data.integration.yuque.token': string
|
||||||
|
// redux/settings/yuqueUrl
|
||||||
|
'data.integration.yuque.url': string
|
||||||
|
// redux/settings/apiServer.apiKey
|
||||||
|
'feature.csaas.api_key': string
|
||||||
|
// redux/settings/apiServer.enabled
|
||||||
|
'feature.csaas.enabled': boolean
|
||||||
|
// redux/settings/apiServer.host
|
||||||
|
'feature.csaas.host': string
|
||||||
|
// redux/settings/apiServer.port
|
||||||
|
'feature.csaas.port': number
|
||||||
|
// redux/settings/maxKeepAliveMinapps
|
||||||
|
'feature.minapp.max_keep_alive': number
|
||||||
|
// redux/settings/minappsOpenLinkExternal
|
||||||
|
'feature.minapp.open_link_external': boolean
|
||||||
|
// redux/settings/showOpenedMinappsInSidebar
|
||||||
|
'feature.minapp.show_opened_in_sidebar': boolean
|
||||||
|
// redux/settings/clickTrayToShowQuickAssistant
|
||||||
|
'feature.quick_assistant.click_tray_to_show': boolean
|
||||||
|
// redux/settings/enableQuickAssistant
|
||||||
|
'feature.quick_assistant.enabled': boolean
|
||||||
|
// redux/settings/readClipboardAtStartup
|
||||||
|
'feature.quick_assistant.read_clipboard_at_startup': boolean
|
||||||
|
// redux/selectionStore/actionItems
|
||||||
|
'feature.selection.action_items': unknown[]
|
||||||
|
// redux/selectionStore/actionWindowOpacity
|
||||||
|
'feature.selection.action_window_opacity': number
|
||||||
|
// redux/selectionStore/selectionEnabled
|
||||||
|
'feature.selection.enabled': boolean
|
||||||
|
// redux/selectionStore/filterList
|
||||||
|
'feature.selection.filter_list': unknown[]
|
||||||
|
// redux/selectionStore/filterMode
|
||||||
|
'feature.selection.filter_mode': string
|
||||||
|
// electronStore/SelectionAssistantFollowToolbar/SelectionAssistantFollowToolbar
|
||||||
|
'feature.selection.follow_toolbar': unknown | null
|
||||||
|
// redux/selectionStore/isAutoClose
|
||||||
|
'feature.selection.is_auto_close': boolean
|
||||||
|
// redux/selectionStore/isAutoPin
|
||||||
|
'feature.selection.is_auto_pin': boolean
|
||||||
|
// redux/selectionStore/isCompact
|
||||||
|
'feature.selection.is_compact': boolean
|
||||||
|
// redux/selectionStore/isFollowToolbar
|
||||||
|
'feature.selection.is_follow_toolbar': boolean
|
||||||
|
// redux/selectionStore/isRemeberWinSize
|
||||||
|
'feature.selection.is_remeber_win_size': boolean
|
||||||
|
// electronStore/SelectionAssistantRemeberWinSize/SelectionAssistantRemeberWinSize
|
||||||
|
'feature.selection.remember_win_size': unknown | null
|
||||||
|
// redux/selectionStore/triggerMode
|
||||||
|
'feature.selection.trigger_mode': string
|
||||||
|
// redux/settings/enableTopicNaming
|
||||||
|
'topic.naming.enabled': boolean
|
||||||
|
// redux/settings/topicNamingPrompt
|
||||||
|
'topic.naming.prompt': string
|
||||||
|
// redux/settings/pinTopicsToTop
|
||||||
|
'topic.pin_to_top': boolean
|
||||||
|
// redux/settings/topicPosition
|
||||||
|
'topic.position': string
|
||||||
|
// redux/settings/showTopicTime
|
||||||
|
'topic.show_time': boolean
|
||||||
|
// redux/settings/assistantIconType
|
||||||
|
'ui.assistant_icon_type': string
|
||||||
|
// redux/settings/clickAssistantToShowTopic
|
||||||
|
'ui.click_assistant_to_show_topic': boolean
|
||||||
|
// redux/settings/customCss
|
||||||
|
'ui.custom_css': string
|
||||||
|
// redux/settings/navbarPosition
|
||||||
|
'ui.navbar.position': string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint sort-keys: ["error", "asc", {"caseSensitive": true, "natural": false}] */
|
/* eslint sort-keys: ["error", "asc", {"caseSensitive": true, "natural": false}] */
|
||||||
export const defaultPreferences: PreferencesType = {
|
export const defaultPreferences: PreferencesType = {
|
||||||
default: {
|
default: {
|
||||||
'app.test5': {
|
'app.developer_mode.enabled': false,
|
||||||
content1: 'test5-1',
|
'app.disable_hardware_acceleration': false,
|
||||||
content2: 2
|
'app.dist.auto_update.enabled': true,
|
||||||
},
|
'app.dist.test_plan.channel': 'UpgradeChannel.LATEST',
|
||||||
'sys.a.test3': true,
|
'app.dist.test_plan.enabled': false,
|
||||||
'sys.a.test4': ['test4-1', 'test4-2'],
|
'app.language': null,
|
||||||
'ui.a.test1': 'test1',
|
'app.launch_on_boot': false,
|
||||||
'ui.b.test2': 1
|
'app.notification.assistant.enabled': false,
|
||||||
|
'app.notification.backup.enabled': false,
|
||||||
|
'app.notification.knowledge.enabled': false,
|
||||||
|
'app.privacy.data_collection.enabled': false,
|
||||||
|
'app.proxy.bypass_rules': null,
|
||||||
|
'app.proxy.mode': 'system',
|
||||||
|
'app.proxy.url': null,
|
||||||
|
'app.spell_check.enabled': false,
|
||||||
|
'app.spell_check.languages': [],
|
||||||
|
'app.theme.mode': 'ThemeMode.system',
|
||||||
|
'app.theme.user_defined': { colorPrimary: '#00b96b' },
|
||||||
|
'app.theme.window_style': 'opaque',
|
||||||
|
'app.tray.enabled': true,
|
||||||
|
'app.tray.on_close': true,
|
||||||
|
'app.tray.on_launch': false,
|
||||||
|
'app.user.id': 'uuid()',
|
||||||
|
'app.user.name': '',
|
||||||
|
'app.zoom_factor': null,
|
||||||
|
'chat.code.collapsible': false,
|
||||||
|
'chat.code.editor.autocompletion': true,
|
||||||
|
'chat.code.editor.fold_gutter': false,
|
||||||
|
'chat.code.editor.highlight_active_line': false,
|
||||||
|
'chat.code.editor.keymap': false,
|
||||||
|
'chat.code.editor.theme_dark': 'auto',
|
||||||
|
'chat.code.editor.theme_light': 'auto',
|
||||||
|
'chat.code.execution.enabled': false,
|
||||||
|
'chat.code.execution.timeout_minutes': 1,
|
||||||
|
'chat.code.image_tools': false,
|
||||||
|
'chat.code.preview.theme_dark': 'auto',
|
||||||
|
'chat.code.preview.theme_light': 'auto',
|
||||||
|
'chat.code.show_line_numbers': false,
|
||||||
|
'chat.code.viewer.theme_dark': 'auto',
|
||||||
|
'chat.code.viewer.theme_light': 'auto',
|
||||||
|
'chat.code.wrappable': false,
|
||||||
|
'chat.input.backspace_delete_model': true,
|
||||||
|
'chat.input.paste_long_text_as_file': false,
|
||||||
|
'chat.input.paste_long_text_threshold': 1500,
|
||||||
|
'chat.input.quick_panel.triggers_enabled': false,
|
||||||
|
'chat.input.send_message_shortcut': 'Enter',
|
||||||
|
'chat.input.show_estimated_tokens': false,
|
||||||
|
'chat.input.translate.auto_translate_with_space': false,
|
||||||
|
'chat.input.translate.show_confirm': true,
|
||||||
|
'chat.message.font': 'system',
|
||||||
|
'chat.message.font_size': 14,
|
||||||
|
'chat.message.math_engine': 'KaTeX',
|
||||||
|
'chat.message.multi_model.fold_display_mode': 'expanded',
|
||||||
|
'chat.message.multi_model.grid_columns': 2,
|
||||||
|
'chat.message.multi_model.grid_popover_trigger': 'click',
|
||||||
|
'chat.message.multi_model.style': 'horizontal',
|
||||||
|
'chat.message.navigation_mode': 'none',
|
||||||
|
'chat.message.show_divider': true,
|
||||||
|
'chat.message.show_prompt': true,
|
||||||
|
'chat.message.show_tokens': true,
|
||||||
|
'chat.message.style': 'plain',
|
||||||
|
'chat.message.thought.auto_collapse': true,
|
||||||
|
'chat.narrow_mode': false,
|
||||||
|
'data.backup.general.skip_backup_file': false,
|
||||||
|
'data.backup.local.auto_sync': false,
|
||||||
|
'data.backup.local.dir': '',
|
||||||
|
'data.backup.local.max_backups': 0,
|
||||||
|
'data.backup.local.skip_backup_file': false,
|
||||||
|
'data.backup.local.sync_interval': 0,
|
||||||
|
'data.backup.nutstore.auto_sync': null,
|
||||||
|
'data.backup.nutstore.path': null,
|
||||||
|
'data.backup.nutstore.skip_backup_file': null,
|
||||||
|
'data.backup.nutstore.sync_interval': null,
|
||||||
|
'data.backup.nutstore.sync_state': null,
|
||||||
|
'data.backup.nutstore.token': null,
|
||||||
|
'data.backup.s3.access_key_id': '',
|
||||||
|
'data.backup.s3.auto_sync': false,
|
||||||
|
'data.backup.s3.bucket': '',
|
||||||
|
'data.backup.s3.endpoint': '',
|
||||||
|
'data.backup.s3.max_backups': 0,
|
||||||
|
'data.backup.s3.region': '',
|
||||||
|
'data.backup.s3.root': '',
|
||||||
|
'data.backup.s3.secret_access_key': '',
|
||||||
|
'data.backup.s3.skip_backup_file': false,
|
||||||
|
'data.backup.s3.sync_interval': 0,
|
||||||
|
'data.backup.webdav.auto_sync': false,
|
||||||
|
'data.backup.webdav.disable_stream': false,
|
||||||
|
'data.backup.webdav.host': '',
|
||||||
|
'data.backup.webdav.max_backups': 0,
|
||||||
|
'data.backup.webdav.pass': '',
|
||||||
|
'data.backup.webdav.path': '/cherry-studio',
|
||||||
|
'data.backup.webdav.skip_backup_file': false,
|
||||||
|
'data.backup.webdav.sync_interval': 0,
|
||||||
|
'data.backup.webdav.user': '',
|
||||||
|
'data.export.markdown.exclude_citations': false,
|
||||||
|
'data.export.markdown.force_dollar_math': false,
|
||||||
|
'data.export.markdown.path': null,
|
||||||
|
'data.export.markdown.show_model_name': false,
|
||||||
|
'data.export.markdown.show_model_provider': false,
|
||||||
|
'data.export.markdown.standardize_citations': false,
|
||||||
|
'data.export.markdown.use_topic_naming_for_message_title': false,
|
||||||
|
'data.export.menus.docx': true,
|
||||||
|
'data.export.menus.image': true,
|
||||||
|
'data.export.menus.joplin': true,
|
||||||
|
'data.export.menus.markdown': true,
|
||||||
|
'data.export.menus.markdown_reason': true,
|
||||||
|
'data.export.menus.notion': true,
|
||||||
|
'data.export.menus.obsidian': true,
|
||||||
|
'data.export.menus.plain_text': true,
|
||||||
|
'data.export.menus.siyuan': true,
|
||||||
|
'data.export.menus.yuque': true,
|
||||||
|
'data.integration.joplin.export_reasoning': false,
|
||||||
|
'data.integration.joplin.token': '',
|
||||||
|
'data.integration.joplin.url': '',
|
||||||
|
'data.integration.notion.api_key': '',
|
||||||
|
'data.integration.notion.database_id': '',
|
||||||
|
'data.integration.notion.export_reasoning': false,
|
||||||
|
'data.integration.notion.page_name_key': 'Name',
|
||||||
|
'data.integration.obsidian.default_vault': null,
|
||||||
|
'data.integration.siyuan.api_url': null,
|
||||||
|
'data.integration.siyuan.box_id': null,
|
||||||
|
'data.integration.siyuan.root_path': null,
|
||||||
|
'data.integration.siyuan.token': null,
|
||||||
|
'data.integration.yuque.repo_id': '',
|
||||||
|
'data.integration.yuque.token': '',
|
||||||
|
'data.integration.yuque.url': '',
|
||||||
|
'feature.csaas.api_key': '`cs-sk-${uuid()}`',
|
||||||
|
'feature.csaas.enabled': false,
|
||||||
|
'feature.csaas.host': 'localhost',
|
||||||
|
'feature.csaas.port': 23333,
|
||||||
|
'feature.minapp.max_keep_alive': 3,
|
||||||
|
'feature.minapp.open_link_external': false,
|
||||||
|
'feature.minapp.show_opened_in_sidebar': true,
|
||||||
|
'feature.quick_assistant.click_tray_to_show': false,
|
||||||
|
'feature.quick_assistant.enabled': false,
|
||||||
|
'feature.quick_assistant.read_clipboard_at_startup': true,
|
||||||
|
'feature.selection.action_items': [],
|
||||||
|
'feature.selection.action_window_opacity': 100,
|
||||||
|
'feature.selection.enabled': false,
|
||||||
|
'feature.selection.filter_list': [],
|
||||||
|
'feature.selection.filter_mode': 'default',
|
||||||
|
'feature.selection.follow_toolbar': null,
|
||||||
|
'feature.selection.is_auto_close': false,
|
||||||
|
'feature.selection.is_auto_pin': false,
|
||||||
|
'feature.selection.is_compact': false,
|
||||||
|
'feature.selection.is_follow_toolbar': true,
|
||||||
|
'feature.selection.is_remeber_win_size': false,
|
||||||
|
'feature.selection.remember_win_size': null,
|
||||||
|
'feature.selection.trigger_mode': 'selected',
|
||||||
|
'topic.naming.enabled': true,
|
||||||
|
'topic.naming.prompt': '',
|
||||||
|
'topic.pin_to_top': false,
|
||||||
|
'topic.position': 'left',
|
||||||
|
'topic.show_time': false,
|
||||||
|
'ui.assistant_icon_type': 'emoji',
|
||||||
|
'ui.click_assistant_to_show_topic': true,
|
||||||
|
'ui.custom_css': '',
|
||||||
|
'ui.navbar.position': 'top'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === AUTO-GENERATED CONTENT END ===
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成统计:
|
||||||
|
* - 总配置项: 158
|
||||||
|
* - electronStore项: 4
|
||||||
|
* - redux项: 154
|
||||||
|
* - localStorage项: 0
|
||||||
|
*/
|
||||||
|
|||||||
152
src/main/data/migrate/electronStoreToPreferences.ts
Normal file
152
src/main/data/migrate/electronStoreToPreferences.ts
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/**
|
||||||
|
* Auto-generated ElectronStore to Preferences migration
|
||||||
|
* Generated at: 2025-08-09T07:20:05.910Z
|
||||||
|
*
|
||||||
|
* === AUTO-GENERATED CONTENT START ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
import dbService from '@data/db/DbService'
|
||||||
|
import { loggerService } from '@logger'
|
||||||
|
import { configManager } from '@main/services/ConfigManager'
|
||||||
|
|
||||||
|
import type { MigrationResult } from './index'
|
||||||
|
import { TypeConverter } from './utils/typeConverters'
|
||||||
|
|
||||||
|
const logger = loggerService.withContext('ElectronStoreMigrator')
|
||||||
|
|
||||||
|
// 键映射表
|
||||||
|
const KEY_MAPPINGS = [
|
||||||
|
{
|
||||||
|
originalKey: 'Language',
|
||||||
|
targetKey: 'app.language',
|
||||||
|
sourceCategory: 'Language',
|
||||||
|
type: 'unknown',
|
||||||
|
defaultValue: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
originalKey: 'SelectionAssistantFollowToolbar',
|
||||||
|
targetKey: 'feature.selection.follow_toolbar',
|
||||||
|
sourceCategory: 'SelectionAssistantFollowToolbar',
|
||||||
|
type: 'unknown',
|
||||||
|
defaultValue: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
originalKey: 'SelectionAssistantRemeberWinSize',
|
||||||
|
targetKey: 'feature.selection.remember_win_size',
|
||||||
|
sourceCategory: 'SelectionAssistantRemeberWinSize',
|
||||||
|
type: 'unknown',
|
||||||
|
defaultValue: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
originalKey: 'ZoomFactor',
|
||||||
|
targetKey: 'app.zoom_factor',
|
||||||
|
sourceCategory: 'ZoomFactor',
|
||||||
|
type: 'unknown',
|
||||||
|
defaultValue: null
|
||||||
|
}
|
||||||
|
] as const
|
||||||
|
|
||||||
|
export class ElectronStoreMigrator {
|
||||||
|
private typeConverter: TypeConverter
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.typeConverter = new TypeConverter()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行ElectronStore到preferences的迁移
|
||||||
|
*/
|
||||||
|
async migrate(): Promise<MigrationResult> {
|
||||||
|
logger.info('开始ElectronStore迁移', { totalItems: KEY_MAPPINGS.length })
|
||||||
|
|
||||||
|
const result: MigrationResult = {
|
||||||
|
success: true,
|
||||||
|
migratedCount: 0,
|
||||||
|
errors: [],
|
||||||
|
source: 'electronStore'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const mapping of KEY_MAPPINGS) {
|
||||||
|
try {
|
||||||
|
await this.migrateItem(mapping)
|
||||||
|
result.migratedCount++
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('迁移单项失败', { mapping, error })
|
||||||
|
result.errors.push({
|
||||||
|
key: mapping.originalKey,
|
||||||
|
error: error instanceof Error ? error.message : String(error)
|
||||||
|
})
|
||||||
|
result.success = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('ElectronStore迁移完成', result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 迁移单个配置项
|
||||||
|
*/
|
||||||
|
private async migrateItem(mapping: (typeof KEY_MAPPINGS)[0]): Promise<void> {
|
||||||
|
const { originalKey, targetKey, type, defaultValue } = mapping
|
||||||
|
|
||||||
|
// 从ElectronStore读取原始值
|
||||||
|
const originalValue = configManager.get(originalKey)
|
||||||
|
|
||||||
|
if (originalValue === undefined || originalValue === null) {
|
||||||
|
// 如果原始值不存在,使用默认值
|
||||||
|
if (defaultValue !== null && defaultValue !== undefined) {
|
||||||
|
const convertedValue = this.typeConverter.convert(defaultValue, type)
|
||||||
|
await dbService.setPreference('default', targetKey, convertedValue)
|
||||||
|
logger.debug('使用默认值迁移', { originalKey, targetKey, defaultValue: convertedValue })
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 类型转换
|
||||||
|
const convertedValue = this.typeConverter.convert(originalValue, type)
|
||||||
|
|
||||||
|
// 写入preferences表
|
||||||
|
await dbService.setPreference('default', targetKey, convertedValue)
|
||||||
|
|
||||||
|
logger.debug('成功迁移配置项', {
|
||||||
|
originalKey,
|
||||||
|
targetKey,
|
||||||
|
originalValue,
|
||||||
|
convertedValue
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证迁移结果
|
||||||
|
*/
|
||||||
|
async validateMigration(): Promise<boolean> {
|
||||||
|
logger.info('开始验证ElectronStore迁移结果')
|
||||||
|
|
||||||
|
for (const mapping of KEY_MAPPINGS) {
|
||||||
|
const { targetKey } = mapping
|
||||||
|
|
||||||
|
try {
|
||||||
|
const value = await dbService.getPreference('default', targetKey)
|
||||||
|
if (value === null) {
|
||||||
|
logger.error('验证失败:配置项不存在', { targetKey })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('验证失败:读取配置项错误', { targetKey, error })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('ElectronStore迁移验证成功')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === AUTO-GENERATED CONTENT END ===
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 迁移统计:
|
||||||
|
* - ElectronStore配置项: 4
|
||||||
|
* - 包含的原始键: Language, SelectionAssistantFollowToolbar, SelectionAssistantRemeberWinSize, ZoomFactor
|
||||||
|
*/
|
||||||
132
src/main/data/migrate/index.ts
Normal file
132
src/main/data/migrate/index.ts
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* Auto-generated migration index
|
||||||
|
* Generated at: 2025-08-09T07:20:05.909Z
|
||||||
|
*
|
||||||
|
* This file is automatically generated from classification.json
|
||||||
|
* To update this file, modify classification.json and run:
|
||||||
|
* node .claude/data-classify/scripts/generate-migration.js
|
||||||
|
*
|
||||||
|
* === AUTO-GENERATED CONTENT START ===
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ElectronStoreMigrator } from './electronStoreToPreferences'
|
||||||
|
import { ReduxMigrator } from './reduxToPreferences'
|
||||||
|
import { loggerService } from '@logger'
|
||||||
|
|
||||||
|
const logger = loggerService.withContext('MigrationManager')
|
||||||
|
|
||||||
|
export interface MigrationResult {
|
||||||
|
success: boolean
|
||||||
|
migratedCount: number
|
||||||
|
errors: Array<{
|
||||||
|
key: string
|
||||||
|
error: string
|
||||||
|
}>
|
||||||
|
source: 'electronStore' | 'redux'
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MigrationSummary {
|
||||||
|
totalItems: number
|
||||||
|
successCount: number
|
||||||
|
errorCount: number
|
||||||
|
electronStore: MigrationResult
|
||||||
|
redux: MigrationResult
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MigrationManager {
|
||||||
|
private electronStoreMigrator: ElectronStoreMigrator
|
||||||
|
private reduxMigrator: ReduxMigrator
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.electronStoreMigrator = new ElectronStoreMigrator()
|
||||||
|
this.reduxMigrator = new ReduxMigrator()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行完整的preferences迁移
|
||||||
|
* @returns 迁移摘要
|
||||||
|
*/
|
||||||
|
async migrateAllPreferences(): Promise<MigrationSummary> {
|
||||||
|
logger.info('开始完整preferences迁移')
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 并行执行两个迁移器
|
||||||
|
const [electronStoreResult, reduxResult] = await Promise.all([
|
||||||
|
this.electronStoreMigrator.migrate(),
|
||||||
|
this.reduxMigrator.migrate()
|
||||||
|
])
|
||||||
|
|
||||||
|
const summary: MigrationSummary = {
|
||||||
|
totalItems: 158,
|
||||||
|
successCount: electronStoreResult.migratedCount + reduxResult.migratedCount,
|
||||||
|
errorCount: electronStoreResult.errors.length + reduxResult.errors.length,
|
||||||
|
electronStore: electronStoreResult,
|
||||||
|
redux: reduxResult
|
||||||
|
}
|
||||||
|
|
||||||
|
if (summary.errorCount > 0) {
|
||||||
|
logger.warn('迁移完成但有错误', { summary })
|
||||||
|
} else {
|
||||||
|
logger.info('迁移完全成功', { summary })
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('迁移过程中发生致命错误', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证迁移结果
|
||||||
|
* @param summary 迁移摘要
|
||||||
|
* @returns 是否验证成功
|
||||||
|
*/
|
||||||
|
async validateMigration(summary: MigrationSummary): Promise<boolean> {
|
||||||
|
logger.info('开始验证迁移结果')
|
||||||
|
|
||||||
|
// 基本验证:检查成功率
|
||||||
|
const successRate = summary.successCount / summary.totalItems
|
||||||
|
if (successRate < 0.95) { // 要求95%以上成功率
|
||||||
|
logger.error('迁移成功率过低', { successRate, summary })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证关键配置项是否存在
|
||||||
|
const criticalKeys = [
|
||||||
|
'app.theme.mode',
|
||||||
|
'app.language',
|
||||||
|
'app.user.id',
|
||||||
|
'feature.quick_assistant.enabled',
|
||||||
|
'chat.message.font_size'
|
||||||
|
]
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dbServiceModule = await import('@main/db/DbService')
|
||||||
|
const dbService = dbServiceModule.default
|
||||||
|
|
||||||
|
for (const key of criticalKeys) {
|
||||||
|
const result = await dbService.getPreference('default', key)
|
||||||
|
if (result === null) {
|
||||||
|
logger.error('关键配置项迁移失败', { key })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('迁移验证成功')
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('验证过程中发生错误', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === AUTO-GENERATED CONTENT END ===
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成统计:
|
||||||
|
* - 总迁移项: 158
|
||||||
|
* - ElectronStore项: 4
|
||||||
|
* - Redux项: 154
|
||||||
|
*/
|
||||||
1081
src/main/data/migrate/reduxToPreferences.ts
Normal file
1081
src/main/data/migrate/reduxToPreferences.ts
Normal file
File diff suppressed because it is too large
Load Diff
72
src/main/data/migrate/utils/migrationHelpers.ts
Normal file
72
src/main/data/migrate/utils/migrationHelpers.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* Migration helper utilities
|
||||||
|
* Generated at: 2025-08-09T07:20:05.912Z
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { loggerService } from '@logger'
|
||||||
|
|
||||||
|
const logger = loggerService.withContext('MigrationHelpers')
|
||||||
|
|
||||||
|
export interface BackupInfo {
|
||||||
|
timestamp: string
|
||||||
|
version: string
|
||||||
|
dataSize: number
|
||||||
|
backupPath: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MigrationHelpers {
|
||||||
|
/**
|
||||||
|
* 创建数据备份
|
||||||
|
*/
|
||||||
|
static async createBackup(): Promise<BackupInfo> {
|
||||||
|
logger.info('开始创建数据备份')
|
||||||
|
|
||||||
|
// 实现备份逻辑
|
||||||
|
const timestamp = new Date().toISOString()
|
||||||
|
const backupInfo: BackupInfo = {
|
||||||
|
timestamp,
|
||||||
|
version: process.env.npm_package_version || 'unknown',
|
||||||
|
dataSize: 0,
|
||||||
|
backupPath: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 实现具体的备份逻辑
|
||||||
|
|
||||||
|
logger.info('数据备份完成', backupInfo)
|
||||||
|
return backupInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证备份完整性
|
||||||
|
*/
|
||||||
|
static async validateBackup(backupInfo: BackupInfo): Promise<boolean> {
|
||||||
|
logger.info('验证备份完整性', backupInfo)
|
||||||
|
|
||||||
|
// TODO: 实现备份验证逻辑
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复备份
|
||||||
|
*/
|
||||||
|
static async restoreBackup(backupInfo: BackupInfo): Promise<boolean> {
|
||||||
|
logger.info('开始恢复备份', backupInfo)
|
||||||
|
|
||||||
|
// TODO: 实现备份恢复逻辑
|
||||||
|
|
||||||
|
logger.info('备份恢复完成')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理临时文件
|
||||||
|
*/
|
||||||
|
static async cleanup(): Promise<void> {
|
||||||
|
logger.info('清理迁移临时文件')
|
||||||
|
|
||||||
|
// TODO: 实现清理逻辑
|
||||||
|
|
||||||
|
logger.info('清理完成')
|
||||||
|
}
|
||||||
|
}
|
||||||
125
src/main/data/migrate/utils/typeConverters.ts
Normal file
125
src/main/data/migrate/utils/typeConverters.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/**
|
||||||
|
* Type conversion utilities for migration
|
||||||
|
* Generated at: 2025-08-09T07:20:05.912Z
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { loggerService } from '@logger'
|
||||||
|
|
||||||
|
const logger = loggerService.withContext('TypeConverter')
|
||||||
|
|
||||||
|
export class TypeConverter {
|
||||||
|
/**
|
||||||
|
* 转换值到指定类型
|
||||||
|
*/
|
||||||
|
convert(value: any, targetType: string): any {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (targetType) {
|
||||||
|
case 'boolean':
|
||||||
|
return this.toBoolean(value)
|
||||||
|
|
||||||
|
case 'string':
|
||||||
|
return this.toString(value)
|
||||||
|
|
||||||
|
case 'number':
|
||||||
|
return this.toNumber(value)
|
||||||
|
|
||||||
|
case 'array':
|
||||||
|
case 'unknown[]':
|
||||||
|
return this.toArray(value)
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
case 'Record<string, unknown>':
|
||||||
|
return this.toObject(value)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// 未知类型,保持原样
|
||||||
|
logger.debug('未知类型,保持原值', { targetType, value })
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('类型转换失败', { value, targetType, error })
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private toBoolean(value: any): boolean {
|
||||||
|
if (typeof value === 'boolean') {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
const lower = value.toLowerCase()
|
||||||
|
return lower === 'true' || lower === '1' || lower === 'yes'
|
||||||
|
}
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return value !== 0
|
||||||
|
}
|
||||||
|
return Boolean(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private toString(value: any): string {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (typeof value === 'number' || typeof value === 'boolean') {
|
||||||
|
return String(value)
|
||||||
|
}
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
return JSON.stringify(value)
|
||||||
|
}
|
||||||
|
return String(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private toNumber(value: any): number {
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
const parsed = parseFloat(value)
|
||||||
|
if (isNaN(parsed)) {
|
||||||
|
logger.warn('字符串无法转换为数字', { value })
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
if (typeof value === 'boolean') {
|
||||||
|
return value ? 1 : 0
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private toArray(value: any): any[] {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(value)
|
||||||
|
return Array.isArray(parsed) ? parsed : [value]
|
||||||
|
} catch {
|
||||||
|
return [value]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [value]
|
||||||
|
}
|
||||||
|
|
||||||
|
private toObject(value: any): Record<string, any> {
|
||||||
|
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(value)
|
||||||
|
return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
|
||||||
|
? parsed
|
||||||
|
: { value }
|
||||||
|
} catch {
|
||||||
|
return { value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { value }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user