Skip to main content

spring_lsp/
macro_analyzer.rs

1//! Rust 宏分析模块
2
3use lsp_types::{Range, Url};
4use syn::__private::Span;
5use syn::spanned::Spanned;
6
7/// Rust 文档模型
8#[derive(Debug, Clone)]
9pub struct RustDocument {
10    /// 文档 URI
11    pub uri: Url,
12    /// 文档内容
13    pub content: String,
14    /// 提取的 spring-rs 宏
15    pub macros: Vec<SpringMacro>,
16}
17
18/// Spring-rs 宏枚举
19#[derive(Debug, Clone)]
20pub enum SpringMacro {
21    /// Service 派生宏
22    DeriveService(ServiceMacro),
23    /// Inject 属性宏
24    Inject(InjectMacro),
25    /// AutoConfig 属性宏
26    AutoConfig(AutoConfigMacro),
27    /// 路由宏
28    Route(RouteMacro),
29    /// 任务调度宏
30    Job(JobMacro),
31}
32
33/// Service 派生宏信息
34#[derive(Debug, Clone)]
35pub struct ServiceMacro {
36    /// 结构体名称
37    pub struct_name: String,
38    /// 字段列表
39    pub fields: Vec<Field>,
40    /// 宏在源代码中的位置
41    pub range: Range,
42}
43
44/// 字段信息
45#[derive(Debug, Clone)]
46pub struct Field {
47    /// 字段名称
48    pub name: String,
49    /// 字段类型名称
50    pub type_name: String,
51    /// 注入宏(如果有)
52    pub inject: Option<InjectMacro>,
53}
54
55/// Inject 属性宏信息
56#[derive(Debug, Clone)]
57pub struct InjectMacro {
58    /// 注入类型
59    pub inject_type: InjectType,
60    /// 组件名称(可选)
61    pub component_name: Option<String>,
62    /// 宏在源代码中的位置
63    pub range: Range,
64}
65
66/// 注入类型
67#[derive(Debug, Clone, PartialEq, Eq)]
68pub enum InjectType {
69    /// 注入组件
70    Component,
71    /// 注入配置
72    Config,
73}
74
75/// AutoConfig 属性宏信息
76#[derive(Debug, Clone)]
77pub struct AutoConfigMacro {
78    /// 配置器类型
79    pub configurator_type: String,
80    /// 宏在源代码中的位置
81    pub range: Range,
82}
83
84/// 路由宏信息
85#[derive(Debug, Clone)]
86pub struct RouteMacro {
87    /// 路由路径
88    pub path: String,
89    /// HTTP 方法列表
90    pub methods: Vec<HttpMethod>,
91    /// 中间件列表
92    pub middlewares: Vec<String>,
93    /// 处理器函数名称
94    pub handler_name: String,
95    /// 宏在源代码中的位置
96    pub range: Range,
97}
98
99/// HTTP 方法
100#[derive(Debug, Clone, PartialEq, Eq, Hash)]
101pub enum HttpMethod {
102    Get,
103    Post,
104    Put,
105    Delete,
106    Patch,
107    Head,
108    Options,
109    Connect,
110    Trace,
111}
112
113impl HttpMethod {
114    /// 从字符串解析 HTTP 方法
115    pub fn parse_method(s: &str) -> Option<Self> {
116        match s.to_uppercase().as_str() {
117            "GET" => Some(HttpMethod::Get),
118            "POST" => Some(HttpMethod::Post),
119            "PUT" => Some(HttpMethod::Put),
120            "DELETE" => Some(HttpMethod::Delete),
121            "PATCH" => Some(HttpMethod::Patch),
122            "HEAD" => Some(HttpMethod::Head),
123            "OPTIONS" => Some(HttpMethod::Options),
124            "CONNECT" => Some(HttpMethod::Connect),
125            "TRACE" => Some(HttpMethod::Trace),
126            _ => None,
127        }
128    }
129
130    /// 转换为字符串
131    pub fn as_str(&self) -> &'static str {
132        match self {
133            HttpMethod::Get => "GET",
134            HttpMethod::Post => "POST",
135            HttpMethod::Put => "PUT",
136            HttpMethod::Delete => "DELETE",
137            HttpMethod::Patch => "PATCH",
138            HttpMethod::Head => "HEAD",
139            HttpMethod::Options => "OPTIONS",
140            HttpMethod::Connect => "CONNECT",
141            HttpMethod::Trace => "TRACE",
142        }
143    }
144}
145
146/// 任务调度宏信息
147#[derive(Debug, Clone)]
148pub enum JobMacro {
149    /// Cron 表达式任务
150    Cron {
151        /// Cron 表达式
152        expression: String,
153        /// 宏在源代码中的位置
154        range: Range,
155    },
156    /// 固定延迟任务
157    FixDelay {
158        /// 延迟秒数
159        seconds: u64,
160        /// 宏在源代码中的位置
161        range: Range,
162    },
163    /// 固定频率任务
164    FixRate {
165        /// 频率秒数
166        seconds: u64,
167        /// 宏在源代码中的位置
168        range: Range,
169    },
170}
171
172/// 宏分析器
173pub struct MacroAnalyzer;
174
175impl MacroAnalyzer {
176    /// 创建新的宏分析器
177    pub fn new() -> Self {
178        Self
179    }
180
181    /// 为宏提供悬停提示
182    ///
183    /// 当用户悬停在 spring-rs 宏上时,显示宏的详细信息和展开后的代码
184    ///
185    /// # Arguments
186    ///
187    /// * `macro_info` - 要显示悬停提示的宏信息
188    ///
189    /// # Returns
190    ///
191    /// 返回格式化的悬停提示内容(Markdown 格式)
192    pub fn hover_macro(&self, macro_info: &SpringMacro) -> String {
193        match macro_info {
194            SpringMacro::DeriveService(service) => self.hover_service_macro(service),
195            SpringMacro::Inject(inject) => self.hover_inject_macro(inject),
196            SpringMacro::AutoConfig(auto_config) => self.hover_auto_config_macro(auto_config),
197            SpringMacro::Route(route) => self.hover_route_macro(route),
198            SpringMacro::Job(job) => self.hover_job_macro(job),
199        }
200    }
201
202    /// 为 Service 宏提供悬停提示
203    ///
204    /// 显示 Service 宏的说明和生成的 trait 实现代码
205    fn hover_service_macro(&self, service: &ServiceMacro) -> String {
206        let mut hover = String::new();
207
208        // 添加标题
209        hover.push_str("# Service 派生宏\n\n");
210
211        // 添加说明
212        hover.push_str("自动为结构体实现依赖注入功能,从应用上下文中获取组件和配置。\n\n");
213
214        // 添加结构体信息
215        hover.push_str(&format!("**结构体**: `{}`\n\n", service.struct_name));
216
217        // 添加字段信息
218        if !service.fields.is_empty() {
219            hover.push_str("**注入字段**:\n\n");
220            for field in &service.fields {
221                hover.push_str(&format!("- `{}`: `{}`", field.name, field.type_name));
222                if let Some(inject) = &field.inject {
223                    match inject.inject_type {
224                        InjectType::Component => {
225                            if let Some(name) = &inject.component_name {
226                                hover.push_str(&format!(" - 注入组件 `\"{}\"`", name));
227                            } else {
228                                hover.push_str(" - 注入组件");
229                            }
230                        }
231                        InjectType::Config => {
232                            hover.push_str(" - 注入配置");
233                        }
234                    }
235                }
236                hover.push('\n');
237            }
238            hover.push('\n');
239        }
240
241        // 添加展开后的代码
242        hover.push_str("**展开后的代码**:\n\n");
243        hover.push_str("```rust\n");
244        hover.push_str(&self.expand_service_macro(service));
245        hover.push_str("```\n");
246
247        hover
248    }
249
250    /// 为 Inject 属性提供悬停提示
251    ///
252    /// 显示注入的组件类型和来源信息
253    fn hover_inject_macro(&self, inject: &InjectMacro) -> String {
254        let mut hover = String::new();
255
256        // 添加标题
257        hover.push_str("# Inject 属性宏\n\n");
258
259        // 添加说明
260        hover.push_str("标记字段从应用上下文中自动注入依赖。\n\n");
261
262        // 添加注入类型信息
263        match inject.inject_type {
264            InjectType::Component => {
265                hover.push_str("**注入类型**: 组件 (Component)\n\n");
266                hover.push_str("从应用上下文中获取已注册的组件实例。\n\n");
267
268                if let Some(name) = &inject.component_name {
269                    hover.push_str(&format!("**组件名称**: `\"{}\"`\n\n", name));
270                    hover.push_str("使用指定名称查找组件,适用于多实例场景(如多数据源)。\n\n");
271                    hover.push_str("**注入代码**:\n\n");
272                    hover.push_str("```rust\n");
273                    hover.push_str(&format!("app.get_component::<T>(\"{}\")\n", name));
274                    hover.push_str("```\n");
275                } else {
276                    hover.push_str("使用类型自动查找组件。\n\n");
277                    hover.push_str("**注入代码**:\n\n");
278                    hover.push_str("```rust\n");
279                    hover.push_str("app.get_component::<T>()\n");
280                    hover.push_str("```\n");
281                }
282            }
283            InjectType::Config => {
284                hover.push_str("**注入类型**: 配置 (Config)\n\n");
285                hover.push_str("从配置文件中加载配置项。\n\n");
286                hover.push_str(
287                    "配置项通过 `#[config_prefix]` 指定的前缀从 `config/app.toml` 中读取。\n\n",
288                );
289                hover.push_str("**注入代码**:\n\n");
290                hover.push_str("```rust\n");
291                hover.push_str("app.get_config::<T>()\n");
292                hover.push_str("```\n");
293            }
294        }
295
296        // 添加示例
297        hover.push_str("\n**使用示例**:\n\n");
298        hover.push_str("```rust\n");
299        hover.push_str("#[derive(Clone, Service)]\n");
300        hover.push_str("struct MyService {\n");
301
302        match inject.inject_type {
303            InjectType::Component => {
304                if let Some(name) = &inject.component_name {
305                    hover.push_str(&format!("    #[inject(component = \"{}\")]\n", name));
306                    hover.push_str("    db: ConnectPool,\n");
307                } else {
308                    hover.push_str("    #[inject(component)]\n");
309                    hover.push_str("    db: ConnectPool,\n");
310                }
311            }
312            InjectType::Config => {
313                hover.push_str("    #[inject(config)]\n");
314                hover.push_str("    config: MyConfig,\n");
315            }
316        }
317
318        hover.push_str("}\n");
319        hover.push_str("```\n");
320
321        hover
322    }
323
324    /// 为 AutoConfig 宏提供悬停提示
325    fn hover_auto_config_macro(&self, auto_config: &AutoConfigMacro) -> String {
326        let mut hover = String::new();
327
328        hover.push_str("# AutoConfig 属性宏\n\n");
329        hover.push_str("自动注册配置器,在应用启动时配置路由、任务等。\n\n");
330        hover.push_str(&format!(
331            "**配置器类型**: `{}`\n\n",
332            auto_config.configurator_type
333        ));
334        hover.push_str("**展开后的代码**:\n\n");
335        hover.push_str("```rust\n");
336        hover.push_str(&self.expand_auto_config_macro(auto_config));
337        hover.push_str("```\n");
338
339        hover
340    }
341
342    /// 为路由宏提供悬停提示
343    fn hover_route_macro(&self, route: &RouteMacro) -> String {
344        let mut hover = String::new();
345
346        hover.push_str("# 路由宏\n\n");
347        hover.push_str("注册 HTTP 路由处理器。\n\n");
348        hover.push_str(&format!("**路由路径**: `{}`\n\n", route.path));
349        hover.push_str(&format!(
350            "**HTTP 方法**: {}\n\n",
351            route
352                .methods
353                .iter()
354                .map(|m| format!("`{}`", m.as_str()))
355                .collect::<Vec<_>>()
356                .join(", ")
357        ));
358
359        if !route.middlewares.is_empty() {
360            hover.push_str(&format!(
361                "**中间件**: {}\n\n",
362                route
363                    .middlewares
364                    .iter()
365                    .map(|m| format!("`{}`", m))
366                    .collect::<Vec<_>>()
367                    .join(", ")
368            ));
369        }
370
371        hover.push_str(&format!("**处理器函数**: `{}`\n\n", route.handler_name));
372        hover.push_str("**展开后的代码**:\n\n");
373        hover.push_str("```rust\n");
374        hover.push_str(&self.expand_route_macro(route));
375        hover.push_str("```\n");
376
377        hover
378    }
379
380    /// 为任务调度宏提供悬停提示
381    fn hover_job_macro(&self, job: &JobMacro) -> String {
382        let mut hover = String::new();
383
384        hover.push_str("# 任务调度宏\n\n");
385
386        match job {
387            JobMacro::Cron { expression, .. } => {
388                hover.push_str("定时任务,使用 Cron 表达式指定执行时间。\n\n");
389                hover.push_str(&format!("**Cron 表达式**: `{}`\n\n", expression));
390                hover.push_str("**格式**: `秒 分 时 日 月 星期`\n\n");
391            }
392            JobMacro::FixDelay { seconds, .. } => {
393                hover.push_str("固定延迟任务,任务完成后延迟指定秒数再次执行。\n\n");
394                hover.push_str(&format!("**延迟秒数**: `{}`\n\n", seconds));
395            }
396            JobMacro::FixRate { seconds, .. } => {
397                hover.push_str("固定频率任务,每隔指定秒数执行一次。\n\n");
398                hover.push_str(&format!("**频率秒数**: `{}`\n\n", seconds));
399            }
400        }
401
402        hover.push_str("**展开后的代码**:\n\n");
403        hover.push_str("```rust\n");
404        hover.push_str(&self.expand_job_macro(job));
405        hover.push_str("```\n");
406
407        hover
408    }
409
410    /// 展开宏,生成展开后的代码
411    ///
412    /// 为 spring-rs 宏生成展开后的 Rust 代码,帮助开发者理解宏的实际效果
413    ///
414    /// # Arguments
415    ///
416    /// * `macro_info` - 要展开的宏信息
417    ///
418    /// # Returns
419    ///
420    /// 返回展开后的 Rust 代码字符串
421    pub fn expand_macro(&self, macro_info: &SpringMacro) -> String {
422        match macro_info {
423            SpringMacro::DeriveService(service) => self.expand_service_macro(service),
424            SpringMacro::Inject(inject) => self.expand_inject_macro(inject),
425            SpringMacro::AutoConfig(auto_config) => self.expand_auto_config_macro(auto_config),
426            SpringMacro::Route(route) => self.expand_route_macro(route),
427            SpringMacro::Job(job) => self.expand_job_macro(job),
428        }
429    }
430
431    /// 展开 Service 派生宏
432    ///
433    /// 生成 Service trait 的实现代码,包括依赖注入逻辑
434    fn expand_service_macro(&self, service: &ServiceMacro) -> String {
435        let struct_name = &service.struct_name;
436        let mut code = String::new();
437
438        // 生成原始结构体定义(带注释)
439        code.push_str("// 原始定义\n");
440        code.push_str("#[derive(Clone)]\n");
441        code.push_str(&format!("pub struct {} {{\n", struct_name));
442        for field in &service.fields {
443            if let Some(inject) = &field.inject {
444                let inject_type = match inject.inject_type {
445                    InjectType::Component => "component",
446                    InjectType::Config => "config",
447                };
448                if let Some(name) = &inject.component_name {
449                    code.push_str(&format!("    #[inject({} = \"{}\")]\n", inject_type, name));
450                } else {
451                    code.push_str(&format!("    #[inject({})]\n", inject_type));
452                }
453            }
454            code.push_str(&format!("    pub {}: {},\n", field.name, field.type_name));
455        }
456        code.push_str("}\n\n");
457
458        // 生成 Service trait 实现
459        code.push_str("// 展开后的代码\n");
460        code.push_str(&format!("impl {} {{\n", struct_name));
461        code.push_str("    /// 从应用上下文构建服务实例\n");
462        code.push_str("    pub fn build(app: &AppBuilder) -> Result<Self> {\n");
463
464        // 为每个字段生成注入代码
465        for field in &service.fields {
466            if let Some(inject) = &field.inject {
467                match inject.inject_type {
468                    InjectType::Component => {
469                        if let Some(name) = &inject.component_name {
470                            code.push_str(&format!(
471                                "        let {} = app.get_component::<{}>(\"{}\")?\n",
472                                field.name, field.type_name, name
473                            ));
474                        } else {
475                            code.push_str(&format!(
476                                "        let {} = app.get_component::<{}>()?;\n",
477                                field.name, field.type_name
478                            ));
479                        }
480                    }
481                    InjectType::Config => {
482                        code.push_str(&format!(
483                            "        let {} = app.get_config::<{}>()?;\n",
484                            field.name, field.type_name
485                        ));
486                    }
487                }
488            } else {
489                // 没有 inject 属性的字段需要手动初始化
490                code.push_str(&format!(
491                    "        let {} = Default::default(); // 需要手动初始化\n",
492                    field.name
493                ));
494            }
495        }
496
497        code.push_str("\n        Ok(Self {\n");
498        for field in &service.fields {
499            code.push_str(&format!("            {},\n", field.name));
500        }
501        code.push_str("        })\n");
502        code.push_str("    }\n");
503        code.push_str("}\n");
504
505        code
506    }
507
508    /// 展开 Inject 属性宏
509    ///
510    /// 生成注入字段的说明
511    fn expand_inject_macro(&self, inject: &InjectMacro) -> String {
512        let mut code = String::new();
513
514        code.push_str("// Inject 属性展开\n");
515        code.push_str("// 这个字段将在运行时从应用上下文中注入\n");
516
517        match inject.inject_type {
518            InjectType::Component => {
519                if let Some(name) = &inject.component_name {
520                    code.push_str("// 注入类型: 组件\n");
521                    code.push_str(&format!("// 组件名称: \"{}\"\n", name));
522                    code.push_str(&format!(
523                        "// 注入代码: app.get_component::<T>(\"{}\")\n",
524                        name
525                    ));
526                } else {
527                    code.push_str("// 注入类型: 组件\n");
528                    code.push_str("// 注入代码: app.get_component::<T>()\n");
529                }
530            }
531            InjectType::Config => {
532                code.push_str("// 注入类型: 配置\n");
533                code.push_str("// 注入代码: app.get_config::<T>()\n");
534            }
535        }
536
537        code
538    }
539
540    /// 展开 AutoConfig 宏
541    ///
542    /// 生成自动配置的说明
543    fn expand_auto_config_macro(&self, auto_config: &AutoConfigMacro) -> String {
544        let mut code = String::new();
545
546        code.push_str("// AutoConfig 宏展开\n");
547        code.push_str(&format!(
548            "// 配置器类型: {}\n",
549            auto_config.configurator_type
550        ));
551        code.push_str("// 这个函数将在应用启动时自动注册配置\n");
552        code.push_str("// 展开后的代码:\n");
553        code.push_str("// \n");
554        code.push_str("// fn main() {\n");
555        code.push_str(&format!(
556            "//     let configurator = {}::new();\n",
557            auto_config.configurator_type
558        ));
559        code.push_str("//     configurator.configure(&mut app);\n");
560        code.push_str("//     // ... 原函数体\n");
561        code.push_str("// }\n");
562
563        code
564    }
565
566    /// 展开路由宏
567    ///
568    /// 生成路由注册代码
569    fn expand_route_macro(&self, route: &RouteMacro) -> String {
570        let mut code = String::new();
571
572        code.push_str("// 路由宏展开\n");
573        code.push_str(&format!("// 路由路径: {}\n", route.path));
574        code.push_str(&format!(
575            "// HTTP 方法: {}\n",
576            route
577                .methods
578                .iter()
579                .map(|m| m.as_str())
580                .collect::<Vec<_>>()
581                .join(", ")
582        ));
583
584        if !route.middlewares.is_empty() {
585            code.push_str(&format!("// 中间件: {}\n", route.middlewares.join(", ")));
586        }
587
588        code.push_str("// \n");
589        code.push_str("// 展开后的代码:\n");
590        code.push_str("// \n");
591
592        for method in &route.methods {
593            code.push_str(&format!(
594                "// router.route(\"{}\", {}, {});\n",
595                route.path,
596                method.as_str().to_lowercase(),
597                route.handler_name
598            ));
599        }
600
601        if !route.middlewares.is_empty() {
602            code.push_str("// \n");
603            code.push_str("// 应用中间件:\n");
604            for middleware in &route.middlewares {
605                code.push_str(&format!("// .layer({})\n", middleware));
606            }
607        }
608
609        code
610    }
611
612    /// 展开任务调度宏
613    ///
614    /// 生成任务调度注册代码
615    fn expand_job_macro(&self, job: &JobMacro) -> String {
616        let mut code = String::new();
617
618        code.push_str("// 任务调度宏展开\n");
619
620        match job {
621            JobMacro::Cron { expression, .. } => {
622                code.push_str("// 任务类型: Cron\n");
623                code.push_str(&format!("// Cron 表达式: {}\n", expression));
624                code.push_str("// \n");
625                code.push_str("// 展开后的代码:\n");
626                code.push_str("// \n");
627                code.push_str("// scheduler.add_job(\n");
628                code.push_str(&format!(
629                    "//     CronJob::new(\"{}\", || async {{\n",
630                    expression
631                ));
632                code.push_str("//         // 任务函数体\n");
633                code.push_str("//     }})\n");
634                code.push_str("// );\n");
635            }
636            JobMacro::FixDelay { seconds, .. } => {
637                code.push_str("// 任务类型: FixDelay\n");
638                code.push_str(&format!("// 延迟秒数: {}\n", seconds));
639                code.push_str("// 说明: 任务完成后延迟指定秒数再次执行\n");
640                code.push_str("// \n");
641                code.push_str("// 展开后的代码:\n");
642                code.push_str("// \n");
643                code.push_str("// scheduler.add_job(\n");
644                code.push_str(&format!(
645                    "//     FixDelayJob::new({}, || async {{\n",
646                    seconds
647                ));
648                code.push_str("//         // 任务函数体\n");
649                code.push_str("//     }})\n");
650                code.push_str("// );\n");
651            }
652            JobMacro::FixRate { seconds, .. } => {
653                code.push_str("// 任务类型: FixRate\n");
654                code.push_str(&format!("// 频率秒数: {}\n", seconds));
655                code.push_str("// 说明: 每隔指定秒数执行一次任务\n");
656                code.push_str("// \n");
657                code.push_str("// 展开后的代码:\n");
658                code.push_str("// \n");
659                code.push_str("// scheduler.add_job(\n");
660                code.push_str(&format!(
661                    "//     FixRateJob::new({}, || async {{\n",
662                    seconds
663                ));
664                code.push_str("//         // 任务函数体\n");
665                code.push_str("//     }})\n");
666                code.push_str("// );\n");
667            }
668        }
669
670        code
671    }
672
673    /// 解析 Rust 源代码
674    ///
675    /// 使用 syn crate 解析 Rust 代码为语法树
676    ///
677    /// # Arguments
678    ///
679    /// * `uri` - 文档 URI
680    /// * `content` - Rust 源代码内容
681    ///
682    /// # Returns
683    ///
684    /// 返回解析后的 RustDocument,如果解析失败则返回错误
685    pub fn parse(&self, uri: Url, content: String) -> Result<RustDocument, syn::Error> {
686        // 使用 syn 解析 Rust 代码
687        let _syntax_tree = syn::parse_file(&content)?;
688
689        // 创建 RustDocument
690        // 注意:实际的宏提取将在 extract_macros 中完成
691        let doc = RustDocument {
692            uri,
693            content,
694            macros: Vec::new(),
695        };
696
697        Ok(doc)
698    }
699
700    /// 从 RustDocument 中提取 spring-rs 宏
701    ///
702    /// 遍历语法树,识别并提取所有 spring-rs 特定的宏
703    ///
704    /// # Arguments
705    ///
706    /// * `doc` - 已解析的 RustDocument
707    ///
708    /// # Returns
709    ///
710    /// 返回包含提取的宏的新 RustDocument
711    pub fn extract_macros(&self, mut doc: RustDocument) -> Result<RustDocument, syn::Error> {
712        // 重新解析内容以获取语法树
713        let syntax_tree = syn::parse_file(&doc.content)?;
714
715        let mut macros = Vec::new();
716
717        // 遍历所有项(items)
718        for item in &syntax_tree.items {
719            match item {
720                // 处理结构体定义
721                syn::Item::Struct(item_struct) => {
722                    // 检查是否有 #[derive(Service)]
723                    if let Some(service_macro) = self.extract_service_macro(item_struct) {
724                        macros.push(SpringMacro::DeriveService(service_macro));
725                    }
726                }
727                // 处理函数定义
728                syn::Item::Fn(item_fn) => {
729                    // 检查路由宏
730                    if let Some(route_macro) = self.extract_route_macro(item_fn) {
731                        macros.push(SpringMacro::Route(route_macro));
732                    }
733
734                    // 检查 AutoConfig 宏
735                    if let Some(auto_config_macro) = self.extract_auto_config_macro(item_fn) {
736                        macros.push(SpringMacro::AutoConfig(auto_config_macro));
737                    }
738
739                    // 检查任务调度宏
740                    if let Some(job_macro) = self.extract_job_macro(item_fn) {
741                        macros.push(SpringMacro::Job(job_macro));
742                    }
743                }
744                _ => {}
745            }
746        }
747
748        doc.macros = macros;
749        Ok(doc)
750    }
751
752    /// 提取 Service 派生宏
753    fn extract_service_macro(&self, item_struct: &syn::ItemStruct) -> Option<ServiceMacro> {
754        // 检查是否有 #[derive(...)] 属性
755        for attr in &item_struct.attrs {
756            if attr.path().is_ident("derive") {
757                // 解析 derive 属性的内容
758                if let Ok(meta_list) = attr.meta.require_list() {
759                    // 检查是否包含 Service
760                    let has_service = meta_list.tokens.to_string().contains("Service");
761
762                    if has_service {
763                        // 提取字段信息
764                        let fields = self.extract_fields(&item_struct.fields);
765
766                        return Some(ServiceMacro {
767                            struct_name: item_struct.ident.to_string(),
768                            fields,
769                            range: self.span_to_range(&item_struct.ident.span()),
770                        });
771                    }
772                }
773            }
774        }
775        None
776    }
777
778    /// 提取结构体字段信息
779    fn extract_fields(&self, fields: &syn::Fields) -> Vec<Field> {
780        let mut result = Vec::new();
781
782        if let syn::Fields::Named(fields_named) = fields {
783            for field in &fields_named.named {
784                if let Some(ident) = &field.ident {
785                    let inject = self.extract_inject_macro(&field.attrs);
786
787                    result.push(Field {
788                        name: ident.to_string(),
789                        type_name: self.type_to_string(&field.ty),
790                        inject,
791                    });
792                }
793            }
794        }
795
796        result
797    }
798
799    /// 提取 Inject 属性宏
800    fn extract_inject_macro(&self, attrs: &[syn::Attribute]) -> Option<InjectMacro> {
801        for attr in attrs {
802            if attr.path().is_ident("inject") {
803                // 解析 inject 属性的参数
804                if let Ok(meta_list) = attr.meta.require_list() {
805                    let tokens_str = meta_list.tokens.to_string();
806
807                    // 判断注入类型
808                    let inject_type = if tokens_str.contains("component") {
809                        InjectType::Component
810                    } else if tokens_str.contains("config") {
811                        InjectType::Config
812                    } else {
813                        continue;
814                    };
815
816                    // 提取组件名称(如果有)
817                    let component_name = self.extract_component_name(&tokens_str);
818
819                    return Some(InjectMacro {
820                        inject_type,
821                        component_name,
822                        range: self.span_to_range(&attr.span()),
823                    });
824                }
825            }
826        }
827        None
828    }
829
830    /// 从 inject 属性参数中提取组件名称
831    fn extract_component_name(&self, tokens_str: &str) -> Option<String> {
832        // 查找 component = "name" 或 component = name 模式
833        if let Some(eq_pos) = tokens_str.find('=') {
834            let after_eq = &tokens_str[eq_pos + 1..].trim();
835            // 移除引号
836            let name = after_eq.trim_matches('"').trim();
837            if !name.is_empty() && name != "component" && name != "config" {
838                return Some(name.to_string());
839            }
840        }
841        None
842    }
843
844    /// 提取路由宏
845    fn extract_route_macro(&self, item_fn: &syn::ItemFn) -> Option<RouteMacro> {
846        for attr in &item_fn.attrs {
847            // 检查各种路由宏
848            let method_and_path: Option<(Vec<HttpMethod>, String)> = if attr.path().is_ident("get")
849            {
850                self.extract_path_from_attr(attr)
851                    .map(|path| (vec![HttpMethod::Get], path))
852            } else if attr.path().is_ident("post") {
853                self.extract_path_from_attr(attr)
854                    .map(|path| (vec![HttpMethod::Post], path))
855            } else if attr.path().is_ident("put") {
856                self.extract_path_from_attr(attr)
857                    .map(|path| (vec![HttpMethod::Put], path))
858            } else if attr.path().is_ident("delete") {
859                self.extract_path_from_attr(attr)
860                    .map(|path| (vec![HttpMethod::Delete], path))
861            } else if attr.path().is_ident("patch") {
862                self.extract_path_from_attr(attr)
863                    .map(|path| (vec![HttpMethod::Patch], path))
864            } else if attr.path().is_ident("head") {
865                self.extract_path_from_attr(attr)
866                    .map(|path| (vec![HttpMethod::Head], path))
867            } else if attr.path().is_ident("options") {
868                self.extract_path_from_attr(attr)
869                    .map(|path| (vec![HttpMethod::Options], path))
870            } else if attr.path().is_ident("route") {
871                // route 宏可以指定多个方法
872                self.extract_route_attr(attr)
873            } else {
874                None
875            };
876
877            if let Some((methods, path)) = method_and_path {
878                // 提取中间件(如果有)
879                let middlewares = self.extract_middlewares(&item_fn.attrs);
880
881                return Some(RouteMacro {
882                    path,
883                    methods,
884                    middlewares,
885                    handler_name: item_fn.sig.ident.to_string(),
886                    range: self.span_to_range(&item_fn.sig.ident.span()),
887                });
888            }
889        }
890        None
891    }
892
893    /// 从属性中提取路径
894    fn extract_path_from_attr(&self, attr: &syn::Attribute) -> Option<String> {
895        // 解析属性参数,期望是字符串字面量
896        if let Ok(meta_list) = attr.meta.require_list() {
897            let tokens_str = meta_list.tokens.to_string();
898            // 移除引号
899            let path = tokens_str.trim().trim_matches('"');
900            return Some(path.to_string());
901        }
902        None
903    }
904
905    /// 从 route 属性中提取路径和方法
906    fn extract_route_attr(&self, attr: &syn::Attribute) -> Option<(Vec<HttpMethod>, String)> {
907        if let Ok(meta_list) = attr.meta.require_list() {
908            let tokens_str = meta_list.tokens.to_string();
909
910            // 提取路径(第一个字符串字面量)
911            let path = if let Some(start) = tokens_str.find('"') {
912                if let Some(end) = tokens_str[start + 1..].find('"') {
913                    tokens_str[start + 1..start + 1 + end].to_string()
914                } else {
915                    return None;
916                }
917            } else {
918                return None;
919            };
920
921            // 提取方法(method = "GET" 或 method = "POST" 等)
922            let mut methods = Vec::new();
923            for part in tokens_str.split(',') {
924                if part.contains("method") {
925                    if let Some(eq_pos) = part.find('=') {
926                        let method_str = part[eq_pos + 1..].trim().trim_matches('"');
927                        if let Some(method) = HttpMethod::parse_method(method_str) {
928                            methods.push(method);
929                        }
930                    }
931                }
932            }
933
934            if !methods.is_empty() {
935                return Some((methods, path));
936            }
937        }
938        None
939    }
940
941    /// 提取中间件列表
942    fn extract_middlewares(&self, attrs: &[syn::Attribute]) -> Vec<String> {
943        let mut middlewares = Vec::new();
944
945        for attr in attrs {
946            if attr.path().is_ident("middlewares") {
947                if let Ok(meta_list) = attr.meta.require_list() {
948                    let tokens_str = meta_list.tokens.to_string();
949                    // 简单解析,按逗号分割
950                    for part in tokens_str.split(',') {
951                        let middleware = part.trim().to_string();
952                        if !middleware.is_empty() {
953                            middlewares.push(middleware);
954                        }
955                    }
956                }
957            }
958        }
959
960        middlewares
961    }
962
963    /// 提取 AutoConfig 宏
964    fn extract_auto_config_macro(&self, item_fn: &syn::ItemFn) -> Option<AutoConfigMacro> {
965        for attr in &item_fn.attrs {
966            if attr.path().is_ident("auto_config") {
967                // 提取配置器类型
968                let configurator_type = if let Ok(meta_list) = attr.meta.require_list() {
969                    meta_list.tokens.to_string()
970                } else {
971                    String::new()
972                };
973
974                return Some(AutoConfigMacro {
975                    configurator_type,
976                    range: self.span_to_range(&attr.span()),
977                });
978            }
979        }
980        None
981    }
982
983    /// 提取任务调度宏
984    fn extract_job_macro(&self, item_fn: &syn::ItemFn) -> Option<JobMacro> {
985        for attr in &item_fn.attrs {
986            if attr.path().is_ident("cron") {
987                // 提取 cron 表达式
988                if let Some(expression) = self.extract_path_from_attr(attr) {
989                    return Some(JobMacro::Cron {
990                        expression,
991                        range: self.span_to_range(&attr.span()),
992                    });
993                }
994            } else if attr.path().is_ident("fix_delay") {
995                // 提取延迟秒数
996                if let Ok(meta_list) = attr.meta.require_list() {
997                    let tokens_str = meta_list.tokens.to_string();
998                    if let Ok(seconds) = tokens_str.trim().parse::<u64>() {
999                        return Some(JobMacro::FixDelay {
1000                            seconds,
1001                            range: self.span_to_range(&attr.span()),
1002                        });
1003                    }
1004                }
1005            } else if attr.path().is_ident("fix_rate") {
1006                // 提取频率秒数
1007                if let Ok(meta_list) = attr.meta.require_list() {
1008                    let tokens_str = meta_list.tokens.to_string();
1009                    if let Ok(seconds) = tokens_str.trim().parse::<u64>() {
1010                        return Some(JobMacro::FixRate {
1011                            seconds,
1012                            range: self.span_to_range(&attr.span()),
1013                        });
1014                    }
1015                }
1016            }
1017        }
1018        None
1019    }
1020
1021    /// 将类型转换为字符串
1022    fn type_to_string(&self, ty: &syn::Type) -> String {
1023        match ty {
1024            syn::Type::Path(type_path) => type_path
1025                .path
1026                .segments
1027                .iter()
1028                .map(|seg| seg.ident.to_string())
1029                .collect::<Vec<_>>()
1030                .join("::"),
1031            _ => "Unknown".to_string(),
1032        }
1033    }
1034
1035    /// 将 Span 转换为 LSP Range
1036    ///
1037    /// 注意:当前实现返回一个默认的 Range,因为 proc_macro2::Span 在非 proc-macro 上下文中
1038    /// 无法获取准确的位置信息。在实际的 LSP 服务器中,我们会使用文档的行列信息。
1039    fn span_to_range(&self, _span: &Span) -> Range {
1040        Range {
1041            start: lsp_types::Position {
1042                line: 0,
1043                character: 0,
1044            },
1045            end: lsp_types::Position {
1046                line: 0,
1047                character: 0,
1048            },
1049        }
1050    }
1051
1052    /// 验证宏参数的正确性
1053    ///
1054    /// 检查宏参数是否符合 spring-rs 的要求,生成错误诊断和修复建议
1055    ///
1056    /// # Arguments
1057    ///
1058    /// * `macro_info` - 要验证的宏信息
1059    ///
1060    /// # Returns
1061    ///
1062    /// 返回诊断信息列表,如果没有错误则返回空列表
1063    pub fn validate_macro(&self, macro_info: &SpringMacro) -> Vec<lsp_types::Diagnostic> {
1064        match macro_info {
1065            SpringMacro::DeriveService(service) => self.validate_service_macro(service),
1066            SpringMacro::Inject(inject) => self.validate_inject_macro(inject),
1067            SpringMacro::AutoConfig(auto_config) => self.validate_auto_config_macro(auto_config),
1068            SpringMacro::Route(route) => self.validate_route_macro(route),
1069            SpringMacro::Job(job) => self.validate_job_macro(job),
1070        }
1071    }
1072
1073    /// 验证 Service 宏
1074    ///
1075    /// 检查结构体字段的 inject 属性是否正确
1076    fn validate_service_macro(&self, service: &ServiceMacro) -> Vec<lsp_types::Diagnostic> {
1077        let mut diagnostics = Vec::new();
1078
1079        // 检查每个字段的 inject 属性
1080        for field in &service.fields {
1081            if let Some(inject) = &field.inject {
1082                // 验证 inject 属性
1083                let inject_diagnostics = self.validate_inject_macro(inject);
1084                diagnostics.extend(inject_diagnostics);
1085
1086                // 检查组件名称是否为空字符串
1087                if let Some(name) = &inject.component_name {
1088                    if name.is_empty() {
1089                        diagnostics.push(lsp_types::Diagnostic {
1090                            range: inject.range,
1091                            severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1092                            code: Some(lsp_types::NumberOrString::String("E001".to_string())),
1093                            source: Some("spring-lsp".to_string()),
1094                            message: format!("字段 '{}' 的组件名称不能为空字符串", field.name),
1095                            related_information: None,
1096                            tags: None,
1097                            code_description: None,
1098                            data: None,
1099                        });
1100                    }
1101                }
1102            }
1103        }
1104
1105        diagnostics
1106    }
1107
1108    /// 验证 Inject 宏
1109    ///
1110    /// 检查注入类型和组件名称是否有效
1111    fn validate_inject_macro(&self, inject: &InjectMacro) -> Vec<lsp_types::Diagnostic> {
1112        let mut diagnostics = Vec::new();
1113
1114        // 检查 config 类型的注入不应该有组件名称
1115        if inject.inject_type == InjectType::Config && inject.component_name.is_some() {
1116            diagnostics.push(lsp_types::Diagnostic {
1117                range: inject.range,
1118                severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1119                code: Some(lsp_types::NumberOrString::String("E002".to_string())),
1120                source: Some("spring-lsp".to_string()),
1121                message: "配置注入 (config) 不应该指定组件名称".to_string(),
1122                related_information: None,
1123                tags: None,
1124                code_description: None,
1125                data: None,
1126            });
1127        }
1128
1129        diagnostics
1130    }
1131
1132    /// 验证 AutoConfig 宏
1133    ///
1134    /// 检查配置器类型是否有效
1135    fn validate_auto_config_macro(
1136        &self,
1137        auto_config: &AutoConfigMacro,
1138    ) -> Vec<lsp_types::Diagnostic> {
1139        let mut diagnostics = Vec::new();
1140
1141        // 检查配置器类型是否为空
1142        if auto_config.configurator_type.is_empty() {
1143            diagnostics.push(lsp_types::Diagnostic {
1144                range: auto_config.range,
1145                severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1146                code: Some(lsp_types::NumberOrString::String("E003".to_string())),
1147                source: Some("spring-lsp".to_string()),
1148                message: "AutoConfig 宏必须指定配置器类型".to_string(),
1149                related_information: None,
1150                tags: None,
1151                code_description: None,
1152                data: None,
1153            });
1154        }
1155
1156        diagnostics
1157    }
1158
1159    /// 验证路由宏
1160    ///
1161    /// 检查路径格式和 HTTP 方法是否有效
1162    fn validate_route_macro(&self, route: &RouteMacro) -> Vec<lsp_types::Diagnostic> {
1163        let mut diagnostics = Vec::new();
1164
1165        // 检查路径是否为空
1166        if route.path.is_empty() {
1167            diagnostics.push(lsp_types::Diagnostic {
1168                range: route.range,
1169                severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1170                code: Some(lsp_types::NumberOrString::String("E004".to_string())),
1171                source: Some("spring-lsp".to_string()),
1172                message: "路由路径不能为空".to_string(),
1173                related_information: None,
1174                tags: None,
1175                code_description: None,
1176                data: None,
1177            });
1178        } else {
1179            // 检查路径是否以 / 开头
1180            if !route.path.starts_with('/') {
1181                diagnostics.push(lsp_types::Diagnostic {
1182                    range: route.range,
1183                    severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1184                    code: Some(lsp_types::NumberOrString::String("E005".to_string())),
1185                    source: Some("spring-lsp".to_string()),
1186                    message: format!("路由路径必须以 '/' 开头,当前路径: '{}'", route.path),
1187                    related_information: None,
1188                    tags: None,
1189                    code_description: None,
1190                    data: None,
1191                });
1192            }
1193
1194            // 检查路径参数格式
1195            self.validate_path_parameters(&route.path, route.range, &mut diagnostics);
1196        }
1197
1198        // 检查是否至少有一个 HTTP 方法
1199        if route.methods.is_empty() {
1200            diagnostics.push(lsp_types::Diagnostic {
1201                range: route.range,
1202                severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1203                code: Some(lsp_types::NumberOrString::String("E006".to_string())),
1204                source: Some("spring-lsp".to_string()),
1205                message: "路由必须至少指定一个 HTTP 方法".to_string(),
1206                related_information: None,
1207                tags: None,
1208                code_description: None,
1209                data: None,
1210            });
1211        }
1212
1213        // 检查处理器函数名称是否为空
1214        if route.handler_name.is_empty() {
1215            diagnostics.push(lsp_types::Diagnostic {
1216                range: route.range,
1217                severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1218                code: Some(lsp_types::NumberOrString::String("E007".to_string())),
1219                source: Some("spring-lsp".to_string()),
1220                message: "路由处理器函数名称不能为空".to_string(),
1221                related_information: None,
1222                tags: None,
1223                code_description: None,
1224                data: None,
1225            });
1226        }
1227
1228        diagnostics
1229    }
1230
1231    /// 验证路径参数格式
1232    ///
1233    /// 检查路径中的参数是否符合 {param} 格式
1234    fn validate_path_parameters(
1235        &self,
1236        path: &str,
1237        range: Range,
1238        diagnostics: &mut Vec<lsp_types::Diagnostic>,
1239    ) {
1240        let mut open_braces = 0;
1241        let mut param_start = None;
1242
1243        for (i, ch) in path.char_indices() {
1244            match ch {
1245                '{' => {
1246                    if open_braces > 0 {
1247                        // 嵌套的大括号
1248                        diagnostics.push(lsp_types::Diagnostic {
1249                            range,
1250                            severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1251                            code: Some(lsp_types::NumberOrString::String("E008".to_string())),
1252                            source: Some("spring-lsp".to_string()),
1253                            message: format!("路径参数不能嵌套,位置: {}", i),
1254                            related_information: None,
1255                            tags: None,
1256                            code_description: None,
1257                            data: None,
1258                        });
1259                    }
1260                    open_braces += 1;
1261                    param_start = Some(i);
1262                }
1263                '}' => {
1264                    if open_braces == 0 {
1265                        // 没有匹配的开括号
1266                        diagnostics.push(lsp_types::Diagnostic {
1267                            range,
1268                            severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1269                            code: Some(lsp_types::NumberOrString::String("E009".to_string())),
1270                            source: Some("spring-lsp".to_string()),
1271                            message: format!("路径参数缺少开括号 '{{', 位置: {}", i),
1272                            related_information: None,
1273                            tags: None,
1274                            code_description: None,
1275                            data: None,
1276                        });
1277                    } else {
1278                        open_braces -= 1;
1279
1280                        // 检查参数名称是否为空
1281                        if let Some(start) = param_start {
1282                            let param_name = &path[start + 1..i];
1283                            if param_name.is_empty() {
1284                                diagnostics.push(lsp_types::Diagnostic {
1285                                    range,
1286                                    severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1287                                    code: Some(lsp_types::NumberOrString::String(
1288                                        "E010".to_string(),
1289                                    )),
1290                                    source: Some("spring-lsp".to_string()),
1291                                    message: format!("路径参数名称不能为空,位置: {}", start),
1292                                    related_information: None,
1293                                    tags: None,
1294                                    code_description: None,
1295                                    data: None,
1296                                });
1297                            } else if !param_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
1298                                // 检查参数名称是否只包含字母、数字和下划线
1299                                diagnostics.push(lsp_types::Diagnostic {
1300                                    range,
1301                                    severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1302                                    code: Some(lsp_types::NumberOrString::String(
1303                                        "E011".to_string(),
1304                                    )),
1305                                    source: Some("spring-lsp".to_string()),
1306                                    message: format!(
1307                                        "路径参数名称只能包含字母、数字和下划线,当前参数: '{}'",
1308                                        param_name
1309                                    ),
1310                                    related_information: None,
1311                                    tags: None,
1312                                    code_description: None,
1313                                    data: None,
1314                                });
1315                            }
1316                        }
1317                        param_start = None;
1318                    }
1319                }
1320                _ => {}
1321            }
1322        }
1323
1324        // 检查是否有未闭合的括号
1325        if open_braces > 0 {
1326            diagnostics.push(lsp_types::Diagnostic {
1327                range,
1328                severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1329                code: Some(lsp_types::NumberOrString::String("E012".to_string())),
1330                source: Some("spring-lsp".to_string()),
1331                message: "路径参数缺少闭括号 '}'".to_string(),
1332                related_information: None,
1333                tags: None,
1334                code_description: None,
1335                data: None,
1336            });
1337        }
1338    }
1339
1340    /// 验证任务调度宏
1341    ///
1342    /// 检查 cron 表达式、延迟和频率值是否有效
1343    fn validate_job_macro(&self, job: &JobMacro) -> Vec<lsp_types::Diagnostic> {
1344        let mut diagnostics = Vec::new();
1345
1346        match job {
1347            JobMacro::Cron { expression, range } => {
1348                // 检查 cron 表达式是否为空
1349                if expression.is_empty() {
1350                    diagnostics.push(lsp_types::Diagnostic {
1351                        range: *range,
1352                        severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1353                        code: Some(lsp_types::NumberOrString::String("E013".to_string())),
1354                        source: Some("spring-lsp".to_string()),
1355                        message: "Cron 表达式不能为空".to_string(),
1356                        related_information: None,
1357                        tags: None,
1358                        code_description: None,
1359                        data: None,
1360                    });
1361                } else {
1362                    // 验证 cron 表达式格式(基本验证)
1363                    self.validate_cron_expression(expression, *range, &mut diagnostics);
1364                }
1365            }
1366            JobMacro::FixDelay { seconds, range } => {
1367                // 检查延迟秒数是否为 0
1368                if *seconds == 0 {
1369                    diagnostics.push(lsp_types::Diagnostic {
1370                        range: *range,
1371                        severity: Some(lsp_types::DiagnosticSeverity::WARNING),
1372                        code: Some(lsp_types::NumberOrString::String("W001".to_string())),
1373                        source: Some("spring-lsp".to_string()),
1374                        message: "延迟秒数为 0 可能不是预期的行为".to_string(),
1375                        related_information: None,
1376                        tags: None,
1377                        code_description: None,
1378                        data: None,
1379                    });
1380                }
1381            }
1382            JobMacro::FixRate { seconds, range } => {
1383                // 检查频率秒数是否为 0
1384                if *seconds == 0 {
1385                    diagnostics.push(lsp_types::Diagnostic {
1386                        range: *range,
1387                        severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1388                        code: Some(lsp_types::NumberOrString::String("E014".to_string())),
1389                        source: Some("spring-lsp".to_string()),
1390                        message: "频率秒数不能为 0".to_string(),
1391                        related_information: None,
1392                        tags: None,
1393                        code_description: None,
1394                        data: None,
1395                    });
1396                }
1397            }
1398        }
1399
1400        diagnostics
1401    }
1402
1403    /// 验证 cron 表达式格式
1404    ///
1405    /// 基本验证 cron 表达式是否符合 "秒 分 时 日 月 星期" 格式
1406    fn validate_cron_expression(
1407        &self,
1408        expression: &str,
1409        range: Range,
1410        diagnostics: &mut Vec<lsp_types::Diagnostic>,
1411    ) {
1412        let parts: Vec<&str> = expression.split_whitespace().collect();
1413
1414        // Cron 表达式应该有 6 个部分:秒 分 时 日 月 星期
1415        if parts.len() != 6 {
1416            diagnostics.push(lsp_types::Diagnostic {
1417                range,
1418                severity: Some(lsp_types::DiagnosticSeverity::ERROR),
1419                code: Some(lsp_types::NumberOrString::String("E015".to_string())),
1420                source: Some("spring-lsp".to_string()),
1421                message: format!(
1422                    "Cron 表达式应该包含 6 个部分(秒 分 时 日 月 星期),当前有 {} 个部分",
1423                    parts.len()
1424                ),
1425                related_information: None,
1426                tags: None,
1427                code_description: None,
1428                data: None,
1429            });
1430        }
1431    }
1432}
1433
1434impl Default for MacroAnalyzer {
1435    fn default() -> Self {
1436        Self::new()
1437    }
1438}
1439
1440#[cfg(test)]
1441mod tests;