From c7ef81842af13b3de2471da09c2152cc21e1fd6f Mon Sep 17 00:00:00 2001 From: nanhaoluo <3075912108@qq.com> Date: Fri, 23 Jan 2026 22:41:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20Mermaid=20?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E7=AE=A1=E7=90=86=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 functions.php 中添加 9 个核心配置管理函数 - argon_get_mermaid_option: 获取配置选项(支持简短名称和完整名称) - argon_update_mermaid_option: 保存配置选项 - argon_validate_mermaid_cdn_url: 验证 CDN URL 格式(必须是有效 URL 且以 .js 结尾) - argon_get_mermaid_theme: 获取当前主题对应的 Mermaid 主题 - argon_get_mermaid_default_config: 获取默认配置 - argon_validate_mermaid_settings: 验证配置选项(CDN 来源、主题名称、布尔值) - argon_init_mermaid_config: 初始化默认配置(不覆盖已有配置) - argon_get_all_mermaid_options: 获取所有配置选项 - argon_update_mermaid_settings: 批量更新配置(包含验证) - 创建单元测试文件验证配置管理功能 - 满足 Requirements 5.1, 5.2, 5.3, 5.4, 5.5 --- functions.php | 236 +++++++++++++++++++++++ tests/run-mermaid-config-tests.php | 234 +++++++++++++++++++++++ tests/test-mermaid-config.php | 293 +++++++++++++++++++++++++++++ 3 files changed, 763 insertions(+) create mode 100644 tests/run-mermaid-config-tests.php create mode 100644 tests/test-mermaid-config.php diff --git a/functions.php b/functions.php index 2884062..d91057c 100644 --- a/functions.php +++ b/functions.php @@ -8937,3 +8937,239 @@ function argon_normalize_social_url($platform, $input) { // 构建完整 URL return esc_url($base_urls[$platform] . $username); } + +// ========================================================================== +// Mermaid 图表支持 - 配置管理 +// ========================================================================== + +/** + * 获取 Mermaid 配置选项 + * + * @param string $option_name 配置选项名称 + * @param mixed $default 默认值 + * @return mixed 配置选项值 + */ +function argon_get_mermaid_option($option_name, $default = null) { + // 配置选项映射表 + $option_map = [ + 'enabled' => 'argon_enable_mermaid', + 'cdn_source' => 'argon_mermaid_cdn_source', + 'custom_cdn_url' => 'argon_mermaid_cdn_custom_url', + 'theme' => 'argon_mermaid_theme', + 'use_local' => 'argon_mermaid_use_local', + 'debug_mode' => 'argon_mermaid_debug_mode' + ]; + + // 如果使用简短名称,转换为完整选项名 + $full_option_name = isset($option_map[$option_name]) ? $option_map[$option_name] : $option_name; + + // 获取选项值 + $value = get_option($full_option_name, $default); + + // 如果值为 null 且有默认值,返回默认值 + if ($value === null && $default !== null) { + return $default; + } + + return $value; +} + +/** + * 保存 Mermaid 配置选项 + * + * @param string $option_name 配置选项名称 + * @param mixed $value 配置选项值 + * @return bool 是否保存成功 + */ +function argon_update_mermaid_option($option_name, $value) { + // 配置选项映射表 + $option_map = [ + 'enabled' => 'argon_enable_mermaid', + 'cdn_source' => 'argon_mermaid_cdn_source', + 'custom_cdn_url' => 'argon_mermaid_cdn_custom_url', + 'theme' => 'argon_mermaid_theme', + 'use_local' => 'argon_mermaid_use_local', + 'debug_mode' => 'argon_mermaid_debug_mode' + ]; + + // 如果使用简短名称,转换为完整选项名 + $full_option_name = isset($option_map[$option_name]) ? $option_map[$option_name] : $option_name; + + // 保存选项值 + return update_option($full_option_name, $value); +} + +/** + * 验证 Mermaid CDN URL 格式 + * + * @param string $url CDN URL + * @return bool 是否为有效的 CDN URL + */ +function argon_validate_mermaid_cdn_url($url) { + // 空 URL 视为无效 + if (empty(trim($url))) { + return false; + } + + // 验证 URL 格式 + if (!filter_var($url, FILTER_VALIDATE_URL)) { + return false; + } + + // 验证是否以 .js 结尾 + if (!preg_match('/\.js$/i', $url)) { + return false; + } + + // 验证协议(必须是 http 或 https) + $parsed_url = parse_url($url); + if (!isset($parsed_url['scheme']) || !in_array($parsed_url['scheme'], ['http', 'https'])) { + return false; + } + + return true; +} + +/** + * 获取当前主题模式对应的 Mermaid 主题 + * + * @return string Mermaid 主题名称 + */ +function argon_get_mermaid_theme() { + // 获取配置的主题 + $configured_theme = argon_get_mermaid_option('theme', 'auto'); + + // 如果不是自动模式,直接返回配置的主题 + if ($configured_theme !== 'auto') { + return $configured_theme; + } + + // 自动模式:根据页面主题返回对应的 Mermaid 主题 + // 注意:这个函数在 PHP 端调用,无法直接检测前端的夜间模式状态 + // 实际的主题切换逻辑应该在 JavaScript 中实现 + // 这里返回默认主题,JavaScript 会根据实际情况覆盖 + return 'default'; +} + +/** + * 获取 Mermaid 配置的默认值 + * + * @return array 默认配置数组 + */ +function argon_get_mermaid_default_config() { + return [ + 'enabled' => false, + 'cdn_source' => 'jsdelivr', + 'custom_cdn_url' => '', + 'theme' => 'auto', + 'use_local' => false, + 'debug_mode' => false + ]; +} + +/** + * 验证 Mermaid 配置选项 + * + * @param array $settings 配置选项数组 + * @return array 错误信息数组,如果没有错误则返回空数组 + */ +function argon_validate_mermaid_settings($settings) { + $errors = []; + + // 验证 CDN 来源 + if (isset($settings['cdn_source'])) { + $valid_sources = ['jsdelivr', 'unpkg', 'custom', 'local']; + if (!in_array($settings['cdn_source'], $valid_sources)) { + $errors[] = __('无效的 CDN 来源', 'argon'); + } + + // 如果选择自定义 CDN,验证 URL + if ($settings['cdn_source'] === 'custom') { + if (!isset($settings['custom_cdn_url']) || empty($settings['custom_cdn_url'])) { + $errors[] = __('自定义 CDN 地址不能为空', 'argon'); + } elseif (!argon_validate_mermaid_cdn_url($settings['custom_cdn_url'])) { + $errors[] = __('CDN 地址格式无效,必须是有效的 URL 且以 .js 结尾', 'argon'); + } + } + } + + // 验证主题名称 + if (isset($settings['theme'])) { + $valid_themes = ['default', 'dark', 'forest', 'neutral', 'auto']; + if (!in_array($settings['theme'], $valid_themes)) { + $errors[] = __('无效的图表主题', 'argon'); + } + } + + // 验证布尔值选项 + $boolean_options = ['enabled', 'use_local', 'debug_mode']; + foreach ($boolean_options as $option) { + if (isset($settings[$option]) && !is_bool($settings[$option]) && !in_array($settings[$option], ['true', 'false', '1', '0', 1, 0], true)) { + $errors[] = sprintf(__('选项 %s 必须是布尔值', 'argon'), $option); + } + } + + return $errors; +} + +/** + * 初始化 Mermaid 默认配置 + * 在主题激活时调用 + */ +function argon_init_mermaid_config() { + $defaults = argon_get_mermaid_default_config(); + + foreach ($defaults as $key => $value) { + // 只在选项不存在时设置默认值 + if (argon_get_mermaid_option($key) === false) { + argon_update_mermaid_option($key, $value); + } + } +} + +/** + * 获取所有 Mermaid 配置选项 + * + * @return array 配置选项数组 + */ +function argon_get_all_mermaid_options() { + $defaults = argon_get_mermaid_default_config(); + $options = []; + + foreach ($defaults as $key => $default_value) { + $options[$key] = argon_get_mermaid_option($key, $default_value); + } + + return $options; +} + +/** + * 批量更新 Mermaid 配置选项 + * + * @param array $settings 配置选项数组 + * @return array 包含 success 和 errors 的结果数组 + */ +function argon_update_mermaid_settings($settings) { + // 验证配置 + $errors = argon_validate_mermaid_settings($settings); + + if (!empty($errors)) { + return [ + 'success' => false, + 'errors' => $errors + ]; + } + + // 保存配置 + $defaults = argon_get_mermaid_default_config(); + foreach ($defaults as $key => $default_value) { + if (isset($settings[$key])) { + argon_update_mermaid_option($key, $settings[$key]); + } + } + + return [ + 'success' => true, + 'errors' => [] + ]; +} diff --git a/tests/run-mermaid-config-tests.php b/tests/run-mermaid-config-tests.php new file mode 100644 index 0000000..041ca50 --- /dev/null +++ b/tests/run-mermaid-config-tests.php @@ -0,0 +1,234 @@ + true, + 'cdn_source' => 'jsdelivr', + 'theme' => 'default', + 'use_local' => false, + 'debug_mode' => false +]; +$errors = argon_validate_mermaid_settings($valid_settings); +test_assert(empty($errors), "测试 15: 验证有效的配置(无错误)"); + +// 测试 16: 验证无效的 CDN 来源 +$invalid_settings = ['cdn_source' => 'invalid_source']; +$errors = argon_validate_mermaid_settings($invalid_settings); +test_assert(!empty($errors), "测试 16: 验证无效的 CDN 来源(有错误)"); + +// 测试 17: 验证自定义 CDN 但 URL 为空 +$invalid_settings = [ + 'cdn_source' => 'custom', + 'custom_cdn_url' => '' +]; +$errors = argon_validate_mermaid_settings($invalid_settings); +test_assert(!empty($errors), "测试 17: 验证自定义 CDN 但 URL 为空(有错误)"); + +// 测试 18: 验证自定义 CDN 但 URL 无效 +$invalid_settings = [ + 'cdn_source' => 'custom', + 'custom_cdn_url' => 'not-a-url' +]; +$errors = argon_validate_mermaid_settings($invalid_settings); +test_assert(!empty($errors), "测试 18: 验证自定义 CDN 但 URL 无效(有错误)"); + +// 测试 19: 验证无效的主题名称 +$invalid_settings = ['theme' => 'invalid_theme']; +$errors = argon_validate_mermaid_settings($invalid_settings); +test_assert(!empty($errors), "测试 19: 验证无效的主题名称(有错误)"); + +// 测试 20: 初始化默认配置 +clear_mermaid_options(); +argon_init_mermaid_config(); +test_assert_equals(false, get_option('argon_enable_mermaid'), "测试 20: 初始化默认配置(enabled 为 false)"); +test_assert_equals('jsdelivr', get_option('argon_mermaid_cdn_source'), "测试 20a: 初始化默认配置(cdn_source 为 jsdelivr)"); + +// 测试 21: 初始化不覆盖已有配置 +clear_mermaid_options(); +update_option('argon_enable_mermaid', true); +argon_init_mermaid_config(); +test_assert_equals(true, get_option('argon_enable_mermaid'), "测试 21: 初始化不覆盖已有配置"); + +// 测试 22: 获取所有配置选项 +clear_mermaid_options(); +update_option('argon_enable_mermaid', true); +update_option('argon_mermaid_cdn_source', 'unpkg'); +$options = argon_get_all_mermaid_options(); +test_assert(is_array($options), "测试 22: 获取所有配置选项(返回数组)"); +test_assert_equals(true, $options['enabled'], "测试 22a: 获取所有配置(enabled 正确)"); +test_assert_equals('unpkg', $options['cdn_source'], "测试 22b: 获取所有配置(cdn_source 正确)"); + +// 测试 23: 批量更新配置(成功) +clear_mermaid_options(); +$settings = [ + 'enabled' => true, + 'cdn_source' => 'jsdelivr', + 'theme' => 'dark' +]; +$result = argon_update_mermaid_settings($settings); +test_assert($result['success'], "测试 23: 批量更新配置(成功)"); +test_assert(empty($result['errors']), "测试 23a: 批量更新配置(无错误)"); +test_assert_equals(true, get_option('argon_enable_mermaid'), "测试 23b: 批量更新配置(enabled 已保存)"); +test_assert_equals('dark', get_option('argon_mermaid_theme'), "测试 23c: 批量更新配置(theme 已保存)"); + +// 测试 24: 批量更新配置(失败) +clear_mermaid_options(); +$settings = ['cdn_source' => 'invalid_source']; +$result = argon_update_mermaid_settings($settings); +test_assert(!$result['success'], "测试 24: 批量更新配置(失败)"); +test_assert(!empty($result['errors']), "测试 24a: 批量更新配置(有错误信息)"); + +// 输出测试结果 +echo "\n=== 测试结果 ===\n"; +echo "总计: {$tests_run} 个测试\n"; +echo "通过: {$tests_passed} 个\n"; +echo "失败: {$tests_failed} 个\n"; + +if ($tests_failed === 0) { + echo "\n✓ 所有测试通过!\n"; + exit(0); +} else { + echo "\n✗ 有测试失败!\n"; + exit(1); +} diff --git a/tests/test-mermaid-config.php b/tests/test-mermaid-config.php new file mode 100644 index 0000000..55cf090 --- /dev/null +++ b/tests/test-mermaid-config.php @@ -0,0 +1,293 @@ +setUp(); // 重用清理逻辑 + parent::tearDown(); + } + + /** + * 测试获取配置选项(使用简短名称) + */ + public function test_get_mermaid_option_with_short_name() { + update_option('argon_enable_mermaid', true); + $this->assertTrue(argon_get_mermaid_option('enabled')); + } + + /** + * 测试获取配置选项(使用完整名称) + */ + public function test_get_mermaid_option_with_full_name() { + update_option('argon_enable_mermaid', true); + $this->assertTrue(argon_get_mermaid_option('argon_enable_mermaid')); + } + + /** + * 测试获取不存在的配置选项(返回默认值) + */ + public function test_get_mermaid_option_with_default() { + $this->assertEquals('default_value', argon_get_mermaid_option('non_existent', 'default_value')); + } + + /** + * 测试保存配置选项(使用简短名称) + */ + public function test_update_mermaid_option_with_short_name() { + $result = argon_update_mermaid_option('enabled', true); + $this->assertTrue($result); + $this->assertTrue(get_option('argon_enable_mermaid')); + } + + /** + * 测试保存配置选项(使用完整名称) + */ + public function test_update_mermaid_option_with_full_name() { + $result = argon_update_mermaid_option('argon_enable_mermaid', true); + $this->assertTrue($result); + $this->assertTrue(get_option('argon_enable_mermaid')); + } + + /** + * 测试验证有效的 CDN URL + */ + public function test_validate_cdn_url_with_valid_url() { + $url = 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js'; + $this->assertTrue(argon_validate_mermaid_cdn_url($url)); + } + + /** + * 测试验证无效的 CDN URL(不是 URL) + */ + public function test_validate_cdn_url_with_invalid_url() { + $url = 'not-a-valid-url'; + $this->assertFalse(argon_validate_mermaid_cdn_url($url)); + } + + /** + * 测试验证无效的 CDN URL(不以 .js 结尾) + */ + public function test_validate_cdn_url_without_js_extension() { + $url = 'https://example.com/mermaid.css'; + $this->assertFalse(argon_validate_mermaid_cdn_url($url)); + } + + /** + * 测试验证空 CDN URL + */ + public function test_validate_cdn_url_with_empty_string() { + $this->assertFalse(argon_validate_mermaid_cdn_url('')); + $this->assertFalse(argon_validate_mermaid_cdn_url(' ')); + } + + /** + * 测试验证无效协议的 CDN URL + */ + public function test_validate_cdn_url_with_invalid_protocol() { + $url = 'ftp://example.com/mermaid.min.js'; + $this->assertFalse(argon_validate_mermaid_cdn_url($url)); + } + + /** + * 测试获取 Mermaid 主题(配置为 default) + */ + public function test_get_mermaid_theme_with_default() { + update_option('argon_mermaid_theme', 'default'); + $this->assertEquals('default', argon_get_mermaid_theme()); + } + + /** + * 测试获取 Mermaid 主题(配置为 dark) + */ + public function test_get_mermaid_theme_with_dark() { + update_option('argon_mermaid_theme', 'dark'); + $this->assertEquals('dark', argon_get_mermaid_theme()); + } + + /** + * 测试获取 Mermaid 主题(配置为 auto) + */ + public function test_get_mermaid_theme_with_auto() { + update_option('argon_mermaid_theme', 'auto'); + // auto 模式在 PHP 端返回 default,实际切换在 JS 端 + $this->assertEquals('default', argon_get_mermaid_theme()); + } + + /** + * 测试获取默认配置 + */ + public function test_get_mermaid_default_config() { + $defaults = argon_get_mermaid_default_config(); + + $this->assertIsArray($defaults); + $this->assertArrayHasKey('enabled', $defaults); + $this->assertArrayHasKey('cdn_source', $defaults); + $this->assertArrayHasKey('theme', $defaults); + $this->assertFalse($defaults['enabled']); + $this->assertEquals('jsdelivr', $defaults['cdn_source']); + $this->assertEquals('auto', $defaults['theme']); + } + + /** + * 测试验证有效的配置 + */ + public function test_validate_mermaid_settings_with_valid_settings() { + $settings = [ + 'enabled' => true, + 'cdn_source' => 'jsdelivr', + 'theme' => 'default', + 'use_local' => false, + 'debug_mode' => false + ]; + + $errors = argon_validate_mermaid_settings($settings); + $this->assertEmpty($errors); + } + + /** + * 测试验证无效的 CDN 来源 + */ + public function test_validate_mermaid_settings_with_invalid_cdn_source() { + $settings = [ + 'cdn_source' => 'invalid_source' + ]; + + $errors = argon_validate_mermaid_settings($settings); + $this->assertNotEmpty($errors); + } + + /** + * 测试验证自定义 CDN 但 URL 为空 + */ + public function test_validate_mermaid_settings_with_custom_cdn_empty_url() { + $settings = [ + 'cdn_source' => 'custom', + 'custom_cdn_url' => '' + ]; + + $errors = argon_validate_mermaid_settings($settings); + $this->assertNotEmpty($errors); + } + + /** + * 测试验证自定义 CDN 但 URL 无效 + */ + public function test_validate_mermaid_settings_with_custom_cdn_invalid_url() { + $settings = [ + 'cdn_source' => 'custom', + 'custom_cdn_url' => 'not-a-url' + ]; + + $errors = argon_validate_mermaid_settings($settings); + $this->assertNotEmpty($errors); + } + + /** + * 测试验证无效的主题名称 + */ + public function test_validate_mermaid_settings_with_invalid_theme() { + $settings = [ + 'theme' => 'invalid_theme' + ]; + + $errors = argon_validate_mermaid_settings($settings); + $this->assertNotEmpty($errors); + } + + /** + * 测试初始化默认配置 + */ + public function test_init_mermaid_config() { + argon_init_mermaid_config(); + + $this->assertFalse(get_option('argon_enable_mermaid')); + $this->assertEquals('jsdelivr', get_option('argon_mermaid_cdn_source')); + $this->assertEquals('auto', get_option('argon_mermaid_theme')); + } + + /** + * 测试初始化不覆盖已有配置 + */ + public function test_init_mermaid_config_does_not_override() { + update_option('argon_enable_mermaid', true); + argon_init_mermaid_config(); + + // 已有配置不应该被覆盖 + $this->assertTrue(get_option('argon_enable_mermaid')); + } + + /** + * 测试获取所有配置选项 + */ + public function test_get_all_mermaid_options() { + update_option('argon_enable_mermaid', true); + update_option('argon_mermaid_cdn_source', 'unpkg'); + + $options = argon_get_all_mermaid_options(); + + $this->assertIsArray($options); + $this->assertTrue($options['enabled']); + $this->assertEquals('unpkg', $options['cdn_source']); + } + + /** + * 测试批量更新配置(成功) + */ + public function test_update_mermaid_settings_success() { + $settings = [ + 'enabled' => true, + 'cdn_source' => 'jsdelivr', + 'theme' => 'dark' + ]; + + $result = argon_update_mermaid_settings($settings); + + $this->assertTrue($result['success']); + $this->assertEmpty($result['errors']); + $this->assertTrue(get_option('argon_enable_mermaid')); + $this->assertEquals('dark', get_option('argon_mermaid_theme')); + } + + /** + * 测试批量更新配置(失败) + */ + public function test_update_mermaid_settings_failure() { + $settings = [ + 'cdn_source' => 'invalid_source' + ]; + + $result = argon_update_mermaid_settings($settings); + + $this->assertFalse($result['success']); + $this->assertNotEmpty($result['errors']); + } +}