Skip to main content

mant_ast/
query.rs

1//! Query envelope combining one structured input with optional tldr content.
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use crate::{
7    MantDocument, OutlineDetail, SearchCase, SearchScope, SearchSyntax, TldrDocument,
8    default_search_limit,
9};
10
11/// Exact schema marker for a complete `ManT` query result.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
13pub enum QuerySchema {
14    /// Query envelope built around `mant.document/v6`.
15    #[serde(rename = "mant.query/v6")]
16    V6,
17}
18
19/// Exact schema marker for a native query request.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
21pub enum RequestSchema {
22    /// Query and projection request accepted through `--request-json`.
23    #[serde(rename = "mant.request/v6")]
24    V6,
25}
26
27/// Source selected by one public query request.
28#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
29#[serde(
30    tag = "kind",
31    rename_all = "kebab-case",
32    rename_all_fields = "camelCase",
33    deny_unknown_fields
34)]
35pub enum QueryInput {
36    /// Resolve a registered Markdown document first, then a local manual page.
37    Document {
38        /// Lookup name shared by registered documents and manual pages.
39        name: String,
40        /// Optional configured Markdown source. It bypasses root documents and manuals.
41        #[serde(skip_serializing_if = "Option::is_none")]
42        source: Option<String>,
43        #[serde(skip_serializing_if = "Option::is_none")]
44        section: Option<String>,
45    },
46    /// Read and parse one local Markdown file.
47    MarkdownFile { path: String },
48}
49
50/// Projection requested after loading one complete structured document.
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
52#[serde(
53    tag = "kind",
54    rename_all = "kebab-case",
55    rename_all_fields = "camelCase",
56    deny_unknown_fields
57)]
58pub enum QueryView {
59    Full {},
60    Outline {
61        detail: OutlineDetail,
62    },
63    Excerpt {
64        #[schemars(length(min = 1))]
65        nodes: Vec<String>,
66    },
67    /// Resolve exactly one semantic entry and return its complete description.
68    Explain {
69        #[schemars(length(min = 1))]
70        entry: String,
71    },
72    Search {
73        #[schemars(length(min = 1, max = 4096))]
74        pattern: String,
75        #[serde(default)]
76        syntax: SearchSyntax,
77        #[serde(default)]
78        case: SearchCase,
79        #[serde(default)]
80        scope: SearchScope,
81        #[serde(default)]
82        word: bool,
83        #[serde(default)]
84        #[schemars(range(max = 100))]
85        context_lines: u16,
86        #[serde(default = "default_search_limit")]
87        #[schemars(range(min = 1, max = 10000))]
88        limit: u32,
89        #[serde(default)]
90        offset: u32,
91    },
92}
93
94/// Native use-case input. The engine validates semantic constraints before I/O.
95#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
96#[serde(rename_all = "camelCase", deny_unknown_fields)]
97#[schemars(extend("$id" = "urn:mant:request:v6"))]
98pub struct QueryRequest {
99    pub schema: RequestSchema,
100    pub input: QueryInput,
101    pub view: QueryView,
102}
103
104/// Native result consumed by JSON, Markdown, and interactive frontends.
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
106#[serde(rename_all = "camelCase")]
107#[schemars(extend("$id" = "urn:mant:query:v6"))]
108pub struct QueryBundle {
109    pub schema: QuerySchema,
110    pub label: String,
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub document: Option<MantDocument>,
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub tldr: Option<TldrDocument>,
115}