use crate::error::RpcError;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use sqry_core::schema::{
ChangeKind as CoreChangeKind, CycleKind as CoreCycleKind, DuplicateKind as CoreDuplicateKind,
OutputFormat as CoreOutputFormat, RelationKind as CoreRelationKind,
UnusedScope as CoreUnusedScope, Visibility as CoreVisibility,
};
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
#[serde(default)]
pub struct SearchFiltersParams {
#[serde(skip_serializing_if = "Vec::is_empty")]
pub language: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visibility: Option<VisibilityParam>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub symbol_kind: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[schemars(range(min = 0.0, max = 1.0))]
pub score_min: Option<f64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum VisibilityParam {
Public,
Private,
}
impl From<VisibilityParam> for CoreVisibility {
fn from(v: VisibilityParam) -> Self {
match v {
VisibilityParam::Public => CoreVisibility::Public,
VisibilityParam::Private => CoreVisibility::Private,
}
}
}
impl From<CoreVisibility> for VisibilityParam {
fn from(v: CoreVisibility) -> Self {
match v {
CoreVisibility::Public => VisibilityParam::Public,
CoreVisibility::Private => VisibilityParam::Private,
}
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
#[serde(default)]
pub struct PaginationParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[schemars(range(min = 1, max = 500))]
pub page_size: Option<i64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum RelationTypeParam {
Callers,
Callees,
Imports,
Exports,
Returns,
}
impl From<RelationTypeParam> for CoreRelationKind {
fn from(r: RelationTypeParam) -> Self {
match r {
RelationTypeParam::Callers => CoreRelationKind::Callers,
RelationTypeParam::Callees => CoreRelationKind::Callees,
RelationTypeParam::Imports => CoreRelationKind::Imports,
RelationTypeParam::Exports => CoreRelationKind::Exports,
RelationTypeParam::Returns => CoreRelationKind::Returns,
}
}
}
impl From<CoreRelationKind> for RelationTypeParam {
fn from(r: CoreRelationKind) -> Self {
match r {
CoreRelationKind::Callers => RelationTypeParam::Callers,
CoreRelationKind::Callees => RelationTypeParam::Callees,
CoreRelationKind::Imports => RelationTypeParam::Imports,
CoreRelationKind::Exports => RelationTypeParam::Exports,
CoreRelationKind::Returns => RelationTypeParam::Returns,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum GraphFormatParam {
#[default]
Json,
Dot,
D2,
Mermaid,
}
impl From<GraphFormatParam> for CoreOutputFormat {
fn from(f: GraphFormatParam) -> Self {
match f {
GraphFormatParam::Json => CoreOutputFormat::Json,
GraphFormatParam::Dot => CoreOutputFormat::Dot,
GraphFormatParam::D2 => CoreOutputFormat::D2,
GraphFormatParam::Mermaid => CoreOutputFormat::Mermaid,
}
}
}
impl From<CoreOutputFormat> for GraphFormatParam {
fn from(f: CoreOutputFormat) -> Self {
match f {
CoreOutputFormat::Json => GraphFormatParam::Json,
CoreOutputFormat::Dot => GraphFormatParam::Dot,
CoreOutputFormat::D2 => GraphFormatParam::D2,
CoreOutputFormat::Mermaid => GraphFormatParam::Mermaid,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum EdgeKindParam {
Calls,
Imports,
Exports,
Returns,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ChangeTypeParam {
Added,
Removed,
Modified,
Renamed,
SignatureChanged,
}
impl From<ChangeTypeParam> for CoreChangeKind {
fn from(c: ChangeTypeParam) -> Self {
match c {
ChangeTypeParam::Added => CoreChangeKind::Added,
ChangeTypeParam::Removed => CoreChangeKind::Removed,
ChangeTypeParam::Modified => CoreChangeKind::Modified,
ChangeTypeParam::Renamed => CoreChangeKind::Renamed,
ChangeTypeParam::SignatureChanged => CoreChangeKind::SignatureChanged,
}
}
}
impl From<CoreChangeKind> for ChangeTypeParam {
fn from(c: CoreChangeKind) -> Self {
match c {
CoreChangeKind::Added => ChangeTypeParam::Added,
CoreChangeKind::Removed => ChangeTypeParam::Removed,
CoreChangeKind::Modified => ChangeTypeParam::Modified,
CoreChangeKind::Renamed => ChangeTypeParam::Renamed,
CoreChangeKind::SignatureChanged => ChangeTypeParam::SignatureChanged,
}
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
#[serde(default)]
pub struct SemanticDiffFiltersParams {
#[serde(skip_serializing_if = "Vec::is_empty")]
pub change_types: Vec<ChangeTypeParam>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub symbol_kinds: Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct GitVersionRefParams {
#[serde(rename = "ref")]
pub git_ref: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_path: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct ReferenceParams {
pub file_path: String,
pub symbol_name: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
#[schemars(example = "json!({
\"query\": \"kind:function name~=/auth/ visibility:public\",
\"path\": \"src/\",
\"max_results\": 50,
\"context_lines\": 3
})")]
pub struct SemanticSearchParams {
pub query: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default)]
pub filters: Option<SearchFiltersParams>,
#[serde(default = "default_max_results_200")]
#[schemars(range(min = 1, max = 10000))]
pub max_results: i64,
#[serde(default = "default_context_lines")]
#[schemars(range(min = 0, max = 20))]
pub context_lines: i64,
#[serde(default)]
pub include_classpath: bool,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
#[schemars(example = "json!({
\"query\": \"kind:class name:UserService\",
\"include_file_context\": true,
\"include_container_context\": true,
\"max_files\": 10
})")]
pub struct HierarchicalSearchParams {
pub query: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default)]
pub filters: Option<SearchFiltersParams>,
#[serde(default = "default_max_results_200")]
#[schemars(range(min = 1, max = 1000))]
pub max_results: i64,
#[serde(default = "default_max_total_symbols")]
#[schemars(range(min = 1, max = 5000))]
pub max_total_symbols: i64,
#[serde(default = "default_context_lines")]
#[schemars(range(min = 0, max = 20))]
pub context_lines: i64,
#[serde(default = "default_true")]
pub auto_merge: bool,
#[serde(default = "default_merge_threshold")]
#[schemars(range(min = 0, max = 1000))]
pub merge_threshold: i64,
#[serde(default = "default_max_files")]
#[schemars(range(min = 1, max = 100))]
pub max_files: i64,
#[serde(default = "default_max_containers_per_file")]
#[schemars(range(min = 1, max = 200))]
pub max_containers_per_file: i64,
#[serde(default = "default_max_symbols_per_container")]
#[schemars(range(min = 1, max = 500))]
pub max_symbols_per_container: i64,
#[serde(default = "default_file_target_tokens")]
#[schemars(range(min = 100, max = 10000))]
pub file_target_tokens: i64,
#[serde(default = "default_container_target_tokens")]
#[schemars(range(min = 100, max = 5000))]
pub container_target_tokens: i64,
#[serde(default = "default_symbol_target_tokens")]
#[schemars(range(min = 50, max = 2000))]
pub symbol_target_tokens: i64,
#[serde(default = "default_context_cluster_target_tokens")]
#[schemars(range(min = 100, max = 2000))]
pub context_cluster_target_tokens: i64,
#[serde(default)]
pub include_file_context: bool,
#[serde(default)]
pub include_container_context: bool,
#[serde(default)]
pub pagination: Option<PaginationParams>,
#[serde(default)]
pub expand_files: Vec<String>,
}
impl HierarchicalSearchParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.query.trim().is_empty() {
return Err(RpcError::validation_with_data(
"query cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "query"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct RelationQueryParams {
pub symbol: String,
pub relation_type: RelationTypeParam,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_depth_1")]
#[schemars(range(min = 1, max = 5))]
pub max_depth: i64,
#[serde(default = "default_max_results_200")]
#[schemars(range(min = 1, max = 5000))]
pub max_results: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(default = "default_page_size_50")]
#[schemars(range(min = 1, max = 500))]
pub page_size: i64,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct ExplainCodeParams {
pub file_path: String,
pub symbol_name: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_true")]
pub include_context: bool,
#[serde(default = "default_true")]
pub include_relations: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct SearchSimilarParams {
pub reference: ReferenceParams,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_similarity_threshold")]
#[schemars(range(min = 0.0, max = 1.0))]
pub similarity_threshold: f64,
#[serde(default = "default_max_results_20")]
#[schemars(range(min = 1, max = 200))]
pub max_results: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(default = "default_page_size_20")]
#[schemars(range(min = 1, max = 200))]
pub page_size: i64,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct ShowDependenciesParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub file_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol_name: Option<String>,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_depth_2")]
#[schemars(range(min = 1, max = 5))]
pub max_depth: i64,
#[serde(default = "default_max_results_500")]
#[schemars(range(min = 1, max = 5000))]
pub max_results: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(default = "default_page_size_100")]
#[schemars(range(min = 1, max = 1000))]
pub page_size: i64,
}
impl ShowDependenciesParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.file_path.is_none() && self.symbol_name.is_none() {
return Err(RpcError::validation_with_data(
"At least one of file_path or symbol_name must be provided",
serde_json::json!({
"kind": "validation",
"constraint": "xor",
"fields": ["file_path", "symbol_name"]
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
pub struct GetIndexStatusParams {
#[serde(default = "default_path")]
pub path: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct ExportGraphParams {
#[serde(default = "default_path")]
pub path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol_name: Option<String>,
#[serde(default)]
pub symbols: Vec<String>,
#[serde(default)]
pub format: GraphFormatParam,
#[serde(default)]
pub verbose: bool,
#[serde(default = "default_max_depth_2")]
#[schemars(range(min = 1, max = 5))]
pub max_depth: i64,
#[serde(default = "default_max_results_1000")]
#[schemars(range(min = 1, max = 5000))]
pub max_results: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(default = "default_page_size_200")]
#[schemars(range(min = 1, max = 1000))]
pub page_size: i64,
#[serde(default)]
pub include: Vec<EdgeKindParam>,
#[serde(default)]
pub languages: Vec<String>,
}
impl ExportGraphParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.file_path.is_none() && self.symbol_name.is_none() && self.symbols.is_empty() {
return Err(RpcError::validation_with_data(
"At least one of file_path, symbol_name, or symbols must be provided",
serde_json::json!({
"kind": "validation",
"constraint": "xor",
"fields": ["file_path", "symbol_name", "symbols"]
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
pub struct CrossLanguageEdgesParams {
#[serde(default = "default_path")]
pub path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub from_lang: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub to_lang: Option<String>,
#[serde(default = "default_max_results_500")]
#[schemars(range(min = 1, max = 5000))]
pub max_results: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(default = "default_page_size_200")]
#[schemars(range(min = 1, max = 1000))]
pub page_size: i64,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct TracePathParams {
pub from_symbol: String,
pub to_symbol: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_hops")]
#[schemars(range(min = 1, max = 10))]
pub max_hops: i64,
#[serde(default = "default_max_paths")]
#[schemars(range(min = 1, max = 20))]
pub max_paths: i64,
#[serde(default = "default_true")]
pub cross_language: bool,
#[serde(default = "default_min_confidence")]
#[schemars(range(min = 0.0, max = 1.0))]
pub min_confidence: f64,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
#[allow(clippy::struct_excessive_bools)] pub struct SubgraphParams {
pub symbols: Vec<String>,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_depth_2")]
#[schemars(range(min = 1, max = 5))]
pub max_depth: i64,
#[serde(default = "default_max_nodes")]
#[schemars(range(min = 1, max = 500))]
pub max_nodes: i64,
#[serde(default = "default_true")]
pub include_callers: bool,
#[serde(default = "default_true")]
pub include_callees: bool,
#[serde(default)]
pub include_imports: bool,
#[serde(default = "default_true")]
pub cross_language: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(default = "default_page_size_50")]
#[schemars(range(min = 1, max = 200))]
pub page_size: i64,
}
impl SubgraphParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.symbols.is_empty() {
return Err(RpcError::validation_with_data(
"symbols array must contain at least one symbol",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "symbols"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct DependencyImpactParams {
pub symbol: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_depth_3")]
#[schemars(range(min = 1, max = 10))]
pub max_depth: i64,
#[serde(default = "default_true")]
pub include_files: bool,
#[serde(default = "default_true")]
pub include_indirect: bool,
#[serde(default = "default_max_results_500")]
#[schemars(range(min = 1, max = 5000))]
pub max_results: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(default = "default_page_size_100")]
#[schemars(range(min = 1, max = 500))]
pub page_size: i64,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct SemanticDiffParams {
pub base: GitVersionRefParams,
pub target: GitVersionRefParams,
#[serde(default = "default_path")]
pub path: String,
#[serde(default)]
pub include_unchanged: bool,
#[serde(default)]
pub filters: Option<SemanticDiffFiltersParams>,
#[serde(default = "default_max_results_500")]
#[schemars(range(min = 1, max = 5000))]
pub max_results: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(default = "default_page_size_100")]
#[schemars(range(min = 1, max = 500))]
pub page_size: i64,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
#[schemars(example = "json!({
\"query\": \"who calls the authenticate function?\",
\"path\": \".\",
\"execute\": true
})")]
pub struct SqryAskParams {
pub query: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default)]
pub execute: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum DuplicateTypeParam {
#[default]
Body,
Signature,
Struct,
}
impl From<DuplicateTypeParam> for CoreDuplicateKind {
fn from(d: DuplicateTypeParam) -> Self {
match d {
DuplicateTypeParam::Body => CoreDuplicateKind::Body,
DuplicateTypeParam::Signature => CoreDuplicateKind::Signature,
DuplicateTypeParam::Struct => CoreDuplicateKind::Struct,
}
}
}
impl From<CoreDuplicateKind> for DuplicateTypeParam {
fn from(d: CoreDuplicateKind) -> Self {
match d {
CoreDuplicateKind::Body => DuplicateTypeParam::Body,
CoreDuplicateKind::Signature => DuplicateTypeParam::Signature,
CoreDuplicateKind::Struct => DuplicateTypeParam::Struct,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum CycleTypeParam {
#[default]
Calls,
Imports,
Modules,
}
impl From<CycleTypeParam> for CoreCycleKind {
fn from(c: CycleTypeParam) -> Self {
match c {
CycleTypeParam::Calls => CoreCycleKind::Calls,
CycleTypeParam::Imports => CoreCycleKind::Imports,
CycleTypeParam::Modules => CoreCycleKind::Modules,
}
}
}
impl From<CoreCycleKind> for CycleTypeParam {
fn from(c: CoreCycleKind) -> Self {
match c {
CoreCycleKind::Calls => CycleTypeParam::Calls,
CoreCycleKind::Imports => CycleTypeParam::Imports,
CoreCycleKind::Modules => CycleTypeParam::Modules,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum UnusedScopeParam {
Public,
Private,
Function,
Struct,
#[default]
All,
}
impl From<UnusedScopeParam> for CoreUnusedScope {
fn from(s: UnusedScopeParam) -> Self {
match s {
UnusedScopeParam::Public => CoreUnusedScope::Public,
UnusedScopeParam::Private => CoreUnusedScope::Private,
UnusedScopeParam::Function => CoreUnusedScope::Function,
UnusedScopeParam::Struct => CoreUnusedScope::Struct,
UnusedScopeParam::All => CoreUnusedScope::All,
}
}
}
impl From<CoreUnusedScope> for UnusedScopeParam {
fn from(s: CoreUnusedScope) -> Self {
match s {
CoreUnusedScope::Public => UnusedScopeParam::Public,
CoreUnusedScope::Private => UnusedScopeParam::Private,
CoreUnusedScope::Function => UnusedScopeParam::Function,
CoreUnusedScope::Struct => UnusedScopeParam::Struct,
CoreUnusedScope::All => UnusedScopeParam::All,
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct FindDuplicatesParams {
#[serde(default = "default_path")]
pub path: String,
#[serde(default)]
pub duplicate_type: DuplicateTypeParam,
#[serde(default = "default_threshold")]
#[schemars(range(min = 0, max = 100))]
pub threshold: i64,
#[serde(default)]
pub exact: bool,
#[serde(default = "default_max_results_100")]
#[schemars(range(min = 1, max = 1000))]
pub max_results: i64,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct FindCyclesParams {
#[serde(default = "default_path")]
pub path: String,
#[serde(default)]
pub cycle_type: CycleTypeParam,
#[serde(default = "default_min_depth")]
#[schemars(range(min = 2))]
pub min_depth: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_depth: Option<i64>,
#[serde(default)]
pub include_self_loops: bool,
#[serde(default = "default_max_results_100")]
#[schemars(range(min = 1, max = 500))]
pub max_results: i64,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct FindUnusedParams {
#[serde(default = "default_path")]
pub path: String,
#[serde(default)]
pub scope: UnusedScopeParam,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub language: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub symbol_kind: Vec<String>,
#[serde(default = "default_max_results_100")]
#[schemars(range(min = 1, max = 1000))]
pub max_results: i64,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
fn default_path() -> String {
".".to_string()
}
fn default_true() -> bool {
true
}
fn default_max_results_20() -> i64 {
20
}
fn default_max_results_200() -> i64 {
200
}
fn default_max_results_500() -> i64 {
500
}
fn default_max_results_1000() -> i64 {
1000
}
fn default_max_total_symbols() -> i64 {
2000
}
fn default_context_lines() -> i64 {
3
}
fn default_merge_threshold() -> i64 {
256
}
fn default_max_files() -> i64 {
20
}
fn default_max_containers_per_file() -> i64 {
50
}
fn default_max_symbols_per_container() -> i64 {
100
}
fn default_file_target_tokens() -> i64 {
2000
}
fn default_container_target_tokens() -> i64 {
1500
}
fn default_symbol_target_tokens() -> i64 {
500
}
fn default_context_cluster_target_tokens() -> i64 {
768
}
fn default_page_size_20() -> i64 {
20
}
fn default_page_size_50() -> i64 {
50
}
fn default_page_size_100() -> i64 {
100
}
fn default_page_size_200() -> i64 {
200
}
fn default_max_depth_1() -> i64 {
1
}
fn default_max_depth_2() -> i64 {
2
}
fn default_max_depth_3() -> i64 {
3
}
fn default_max_hops() -> i64 {
5
}
fn default_max_paths() -> i64 {
5
}
fn default_max_nodes() -> i64 {
50
}
fn default_similarity_threshold() -> f64 {
0.7
}
fn default_min_confidence() -> f64 {
0.5
}
fn default_threshold() -> i64 {
80
}
fn default_max_results_100() -> i64 {
100
}
fn default_min_depth() -> i64 {
2
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct IsNodeInCycleParams {
pub symbol: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default)]
pub cycle_type: CycleTypeParam,
#[serde(default = "default_cycle_min_depth")]
#[schemars(range(min = 1, max = 100))]
pub min_depth: usize,
#[schemars(range(min = 1, max = 100))]
pub max_depth: Option<usize>,
#[serde(default)]
pub include_self_loops: bool,
}
fn default_cycle_min_depth() -> usize {
2
}
impl IsNodeInCycleParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.symbol.trim().is_empty() {
return Err(RpcError::validation_with_data(
"symbol cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "symbol"
}),
));
}
if self.min_depth < 1 {
return Err(RpcError::validation_with_data(
"min_depth must be at least 1",
serde_json::json!({
"kind": "validation",
"constraint": "range",
"field": "min_depth",
"min": 1,
"actual": self.min_depth
}),
));
}
if let Some(max) = self.max_depth {
if max < 1 {
return Err(RpcError::validation_with_data(
"max_depth must be at least 1",
serde_json::json!({
"kind": "validation",
"constraint": "range",
"field": "max_depth",
"min": 1,
"actual": max
}),
));
}
if max < self.min_depth {
return Err(RpcError::validation_with_data(
"max_depth must be >= min_depth",
serde_json::json!({
"kind": "validation",
"constraint": "ordering",
"field": "max_depth",
"min_depth": self.min_depth,
"max_depth": max
}),
));
}
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct PatternSearchParams {
pub pattern: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_results_100")]
#[schemars(range(min = 1, max = 1000))]
pub max_results: i64,
#[serde(default)]
pub include_classpath: bool,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
impl PatternSearchParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.pattern.trim().is_empty() {
return Err(RpcError::validation_with_data(
"pattern cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "pattern"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct DirectCallersParams {
pub symbol: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_results_100")]
#[schemars(range(min = 1, max = 500))]
pub max_results: i64,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
impl DirectCallersParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.symbol.trim().is_empty() {
return Err(RpcError::validation_with_data(
"symbol cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "symbol"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct DirectCalleesParams {
pub symbol: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_results_100")]
#[schemars(range(min = 1, max = 500))]
pub max_results: i64,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
impl DirectCalleesParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.symbol.trim().is_empty() {
return Err(RpcError::validation_with_data(
"symbol cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "symbol"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct ListFilesParams {
#[serde(default = "default_path")]
pub path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(default = "default_max_results_500")]
#[schemars(range(min = 1, max = 10000))]
pub max_results: i64,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct ListSymbolsParams {
#[serde(default = "default_path")]
pub path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(default = "default_max_results_500")]
#[schemars(range(min = 1, max = 10000))]
pub max_results: i64,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
pub struct GetGraphStatsParams {
#[serde(default = "default_path")]
pub path: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct GetDefinitionParams {
pub symbol: String,
#[serde(default = "default_path")]
pub path: String,
}
impl GetDefinitionParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.symbol.trim().is_empty() {
return Err(RpcError::validation_with_data(
"symbol cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "symbol"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct GetReferencesParams {
pub symbol: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_true")]
pub include_declaration: bool,
#[serde(default = "default_max_results_100")]
#[schemars(range(min = 1, max = 1000))]
pub max_results: i64,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
impl GetReferencesParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.symbol.trim().is_empty() {
return Err(RpcError::validation_with_data(
"symbol cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "symbol"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct GetHoverInfoParams {
pub symbol: String,
#[serde(default = "default_path")]
pub path: String,
}
impl GetHoverInfoParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.symbol.trim().is_empty() {
return Err(RpcError::validation_with_data(
"symbol cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "symbol"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct GetDocumentSymbolsParams {
pub file_path: String,
#[serde(default = "default_path")]
pub path: String,
}
impl GetDocumentSymbolsParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.file_path.trim().is_empty() {
return Err(RpcError::validation_with_data(
"file_path cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "file_path"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct GetWorkspaceSymbolsParams {
pub query: String,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_results_100")]
#[schemars(range(min = 1, max = 1000))]
pub max_results: i64,
#[serde(default)]
pub pagination: Option<PaginationParams>,
}
impl GetWorkspaceSymbolsParams {
pub fn validate(&self) -> Result<(), RpcError> {
if self.query.trim().is_empty() {
return Err(RpcError::validation_with_data(
"query cannot be empty",
serde_json::json!({
"kind": "validation",
"constraint": "non_empty",
"field": "query"
}),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
pub struct GetInsightsParams {
#[serde(default = "default_path")]
pub path: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct ComplexityMetricsParams {
#[serde(default = "default_path")]
pub path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<String>,
#[serde(default = "default_min_complexity")]
#[schemars(range(min = 1, max = 100))]
pub min_complexity: u32,
#[serde(default = "default_true")]
pub sort_by_complexity: bool,
#[serde(default = "default_max_results_100")]
#[schemars(range(min = 1, max = 1000))]
pub max_results: i64,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
pub struct RebuildIndexParams {
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_true")]
pub force: bool,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)]
pub struct ExpandCacheStatusParams {
#[serde(default = "default_path")]
pub path: String,
}
fn default_min_complexity() -> u32 {
1
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum CallHierarchyDirection {
Incoming,
Outgoing,
}
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
pub struct CallHierarchyParams {
pub symbol: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub file_path: Option<String>,
pub direction: CallHierarchyDirection,
#[serde(default = "default_path")]
pub path: String,
#[serde(default = "default_max_depth_1")]
#[schemars(range(min = 1, max = 5))]
pub max_depth: i64,
#[serde(default = "default_max_results_200")]
#[schemars(range(min = 1, max = 5000))]
pub max_results: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_token: Option<String>,
#[serde(default = "default_page_size_50")]
#[schemars(range(min = 1, max = 500))]
pub page_size: i64,
}
#[cfg(test)]
mod tests {
use super::*;
use schemars::schema_for;
#[test]
fn test_semantic_search_params_deser() {
let json = r#"{"query": "test"}"#;
let params: SemanticSearchParams = serde_json::from_str(json).unwrap();
assert_eq!(params.query, "test");
assert_eq!(params.path, ".");
assert_eq!(params.max_results, 200);
}
#[test]
fn test_show_dependencies_xor_valid() {
let params = ShowDependenciesParams {
file_path: Some("test.rs".to_string()),
symbol_name: None,
path: ".".to_string(),
max_depth: 2,
max_results: 500,
page_token: None,
page_size: 100,
};
assert!(params.validate().is_ok());
}
#[test]
fn test_show_dependencies_xor_invalid() {
let params = ShowDependenciesParams {
file_path: None,
symbol_name: None,
path: ".".to_string(),
max_depth: 2,
max_results: 500,
page_token: None,
page_size: 100,
};
assert!(params.validate().is_err());
}
#[test]
fn test_subgraph_non_empty_valid() {
let params = SubgraphParams {
symbols: vec!["foo".to_string()],
path: ".".to_string(),
max_depth: 2,
max_nodes: 50,
include_callers: true,
include_callees: true,
include_imports: false,
cross_language: true,
page_token: None,
page_size: 50,
};
assert!(params.validate().is_ok());
}
#[test]
fn test_subgraph_non_empty_invalid() {
let params = SubgraphParams {
symbols: vec![],
path: ".".to_string(),
max_depth: 2,
max_nodes: 50,
include_callers: true,
include_callees: true,
include_imports: false,
cross_language: true,
page_token: None,
page_size: 50,
};
assert!(params.validate().is_err());
}
#[test]
fn test_schema_generation() {
let _ = schema_for!(SemanticSearchParams);
let _ = schema_for!(HierarchicalSearchParams);
let _ = schema_for!(RelationQueryParams);
let _ = schema_for!(ExplainCodeParams);
let _ = schema_for!(SearchSimilarParams);
let _ = schema_for!(ShowDependenciesParams);
let _ = schema_for!(GetIndexStatusParams);
let _ = schema_for!(ExportGraphParams);
let _ = schema_for!(CrossLanguageEdgesParams);
let _ = schema_for!(TracePathParams);
let _ = schema_for!(SubgraphParams);
let _ = schema_for!(DependencyImpactParams);
let _ = schema_for!(SemanticDiffParams);
let _ = schema_for!(SqryAskParams);
let _ = schema_for!(FindCyclesParams);
let _ = schema_for!(FindDuplicatesParams);
let _ = schema_for!(FindUnusedParams);
let _ = schema_for!(IsNodeInCycleParams);
let _ = schema_for!(PatternSearchParams);
let _ = schema_for!(DirectCallersParams);
let _ = schema_for!(DirectCalleesParams);
}
#[test]
fn test_is_node_in_cycle_valid() {
let params = IsNodeInCycleParams {
symbol: "my_function".to_string(),
path: ".".to_string(),
cycle_type: CycleTypeParam::Calls,
min_depth: 2,
max_depth: None,
include_self_loops: false,
};
assert!(params.validate().is_ok());
}
#[test]
fn test_is_node_in_cycle_empty_symbol_invalid() {
let params = IsNodeInCycleParams {
symbol: String::new(),
path: ".".to_string(),
cycle_type: CycleTypeParam::Calls,
min_depth: 2,
max_depth: None,
include_self_loops: false,
};
assert!(params.validate().is_err());
}
#[test]
fn test_is_node_in_cycle_whitespace_symbol_invalid() {
let params = IsNodeInCycleParams {
symbol: " ".to_string(),
path: ".".to_string(),
cycle_type: CycleTypeParam::Imports,
min_depth: 2,
max_depth: None,
include_self_loops: false,
};
assert!(params.validate().is_err());
}
#[test]
fn test_is_node_in_cycle_min_depth_zero_invalid() {
let params = IsNodeInCycleParams {
symbol: "my_function".to_string(),
path: ".".to_string(),
cycle_type: CycleTypeParam::Calls,
min_depth: 0,
max_depth: None,
include_self_loops: false,
};
let err = params.validate().unwrap_err();
assert!(err.message.contains("min_depth must be at least 1"));
}
#[test]
fn test_is_node_in_cycle_max_depth_zero_invalid() {
let params = IsNodeInCycleParams {
symbol: "my_function".to_string(),
path: ".".to_string(),
cycle_type: CycleTypeParam::Calls,
min_depth: 1,
max_depth: Some(0),
include_self_loops: false,
};
let err = params.validate().unwrap_err();
assert!(err.message.contains("max_depth must be at least 1"));
}
#[test]
fn test_is_node_in_cycle_max_depth_less_than_min_depth_invalid() {
let params = IsNodeInCycleParams {
symbol: "my_function".to_string(),
path: ".".to_string(),
cycle_type: CycleTypeParam::Calls,
min_depth: 5,
max_depth: Some(3),
include_self_loops: false,
};
let err = params.validate().unwrap_err();
assert!(err.message.contains("max_depth must be >= min_depth"));
}
#[test]
fn test_is_node_in_cycle_valid_depth_ranges() {
let params = IsNodeInCycleParams {
symbol: "my_function".to_string(),
path: ".".to_string(),
cycle_type: CycleTypeParam::Calls,
min_depth: 1,
max_depth: None,
include_self_loops: true,
};
assert!(params.validate().is_ok());
let params = IsNodeInCycleParams {
symbol: "my_function".to_string(),
path: ".".to_string(),
cycle_type: CycleTypeParam::Calls,
min_depth: 3,
max_depth: Some(3),
include_self_loops: false,
};
assert!(params.validate().is_ok());
let params = IsNodeInCycleParams {
symbol: "my_function".to_string(),
path: ".".to_string(),
cycle_type: CycleTypeParam::Calls,
min_depth: 2,
max_depth: Some(10),
include_self_loops: false,
};
assert!(params.validate().is_ok());
}
#[test]
fn test_pattern_search_valid() {
let params = PatternSearchParams {
pattern: "test".to_string(),
path: ".".to_string(),
max_results: 100,
include_classpath: false,
pagination: None,
};
assert!(params.validate().is_ok());
}
#[test]
fn test_pattern_search_empty_pattern_invalid() {
let params = PatternSearchParams {
pattern: String::new(),
path: ".".to_string(),
max_results: 100,
include_classpath: false,
pagination: None,
};
assert!(params.validate().is_err());
}
#[test]
fn test_pattern_search_whitespace_pattern_invalid() {
let params = PatternSearchParams {
pattern: " ".to_string(),
path: ".".to_string(),
max_results: 100,
include_classpath: false,
pagination: None,
};
assert!(params.validate().is_err());
}
#[test]
fn test_direct_callers_valid() {
let params = DirectCallersParams {
symbol: "my_function".to_string(),
path: ".".to_string(),
max_results: 100,
pagination: None,
};
assert!(params.validate().is_ok());
}
#[test]
fn test_direct_callers_empty_symbol_invalid() {
let params = DirectCallersParams {
symbol: String::new(),
path: ".".to_string(),
max_results: 100,
pagination: None,
};
assert!(params.validate().is_err());
}
#[test]
fn test_direct_callers_whitespace_symbol_invalid() {
let params = DirectCallersParams {
symbol: " ".to_string(),
path: ".".to_string(),
max_results: 100,
pagination: None,
};
assert!(params.validate().is_err());
}
#[test]
fn test_direct_callees_valid() {
let params = DirectCalleesParams {
symbol: "my_function".to_string(),
path: ".".to_string(),
max_results: 100,
pagination: None,
};
assert!(params.validate().is_ok());
}
#[test]
fn test_direct_callees_empty_symbol_invalid() {
let params = DirectCalleesParams {
symbol: String::new(),
path: ".".to_string(),
max_results: 100,
pagination: None,
};
assert!(params.validate().is_err());
}
#[test]
fn test_direct_callees_whitespace_symbol_invalid() {
let params = DirectCalleesParams {
symbol: " ".to_string(),
path: ".".to_string(),
max_results: 100,
pagination: None,
};
assert!(params.validate().is_err());
}
}